$iMaxLen) { $s = mb_substr($s, 0, $iMaxLen); $sTail = $sEllipsisSign; } return htmlspecialchars_adv($s) . $sTail; } function html2txt($content, $tags = "") { while($content != strip_tags($content, $tags)) { $content = strip_tags($content, $tags); } return $content; } /** * Functions to process user input. * DON'T use to process data before passing to SQL query - use db prepare instead @see BxDolDb::prepare. * It is ok to use bx_process_input and then db prepare. * @param $mixedData data to process * @param $iDataType how to handle data, possible valies: * @code * BX_DATA_INT - integer value * BX_DATA_FLOAT - float values * BX_DATA_CHECKBOX - 'on' or empty string * BX_DATA_TEXT - text data, single line (default) * BX_DATA_TEXT_MULTILINE - text data, multiple lines * BX_DATA_HTML - HTML data * BX_DATA_DATE - date data type stored as yyyy-mm-dd * BX_DATA_DATETIME - date/time data type stored as yyyy-mm-dd hh:mm:ss * BX_DATA_DATE_TS' - date data type stored as unixtimestamp * BX_DATA_DATETIME_TS - date/time data type stored as unixtimestamp * BX_DATA_DATE_TS_UTC - date data type stored as unixtimestamp from UTC time * BX_DATA_DATETIME_TS_UTC - date/time data type stored as unixtimestamp from UTC time * @endcode * @param $mixedParams optional parameters to pass for validation * @param $isCheckMagicQuotes deprecated * @return the filtered data, or FALSE if the filter fails. */ function bx_process_input ($mixedData, $iDataType = BX_DATA_TEXT, $mixedParams = false, $isCheckMagicQuotes = true) { if (is_array($mixedData)) { foreach ($mixedData as $k => $v) $mixedData[$k] = bx_process_input($v, $iDataType, $mixedParams); return $mixedData; } switch ($iDataType) { case BX_DATA_INT: return filter_var(trim($mixedData), FILTER_VALIDATE_INT); case BX_DATA_FLOAT: return filter_var(trim($mixedData), FILTER_VALIDATE_FLOAT); case BX_DATA_CHECKBOX: return 'on' == trim($mixedData) ? 'on' : ''; case BX_DATA_DATE: // maybe consider using strtotime $mixedData = trim($mixedData); if (!preg_match('/^\d{4}-\d{1,2}-\d{1,2}$/', $mixedData)) return false; list($iYear, $iMonth, $iDay) = explode('-', $mixedData); // 1985-10-28 $iDay = intval($iDay); $iMonth = intval($iMonth); $iYear = intval($iYear); return sprintf("%04d-%02d-%02d", $iYear, $iMonth, $iDay); case BX_DATA_DATETIME: // maybe consider using strtotime $mixedData = trim($mixedData); if (!preg_match('#(\d+)\-(\d+)\-(\d+)[\sT]{1}(\d+):(\d+):(\d+)#', $mixedData, $m) && !preg_match('#(\d+)\-(\d+)\-(\d+)[\sT]{1}(\d+):(\d+)#', $mixedData, $m)) return bx_process_input ($mixedData, BX_DATA_DATE, $mixedParams, $isCheckMagicQuotes); $iDay = intval($m[3]); $iMonth = intval($m[2]); $iYear = intval($m[1]); $iH = intval($m[4]); $iM = intval($m[5]); $iS = isset($m[6]) ? intval($m[6]) : 0; return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $iYear, $iMonth, $iDay, $iH, $iM, $iS); // 1985-10-28 00:59:35 case BX_DATA_DATE_TS: case BX_DATA_DATE_TS_UTC: $mixedData = trim($mixedData); if (!preg_match('/^\d{4}-\d{1,2}-\d{1,2}$/', $mixedData)) return false; list($iYear, $iMonth, $iDay) = explode('-', $mixedData); $iDay = intval($iDay); $iMonth = intval($iMonth); $iYear = intval($iYear); $sFunc = BX_DATA_DATE_TS_UTC == $iDataType ? 'gmmktime' : 'mktime'; $iRet = $sFunc (0, 0, 0, $iMonth, $iDay, $iYear); return $iRet > 0 ? $iRet : false; case BX_DATA_DATETIME_TS: case BX_DATA_DATETIME_TS_UTC: if (!preg_match('#(\d+)\-(\d+)\-(\d+)[\s]{1}(\d+):(\d+):(\d+)[\s]{1}([+\-\d:Z]+)#', $mixedData, $m) && !preg_match('#(\d+)\-(\d+)\-(\d+)[\sT]{1}(\d+):(\d+):(\d+)#', $mixedData, $m) && !preg_match('#(\d+)\-(\d+)\-(\d+)[\sT]{1}(\d+):(\d+)#', $mixedData, $m)) return bx_process_input ($mixedData, BX_DATA_DATETIME_TS == $iDataType ? BX_DATA_DATE_TS : BX_DATA_DATE_TS_UTC, $mixedParams, $isCheckMagicQuotes); $iDay = $m[3]; $iMonth = $m[2]; $iYear = $m[1]; $iH = $m[4]; $iM = $m[5]; $iS = isset($m[6]) ? $m[6] : 0; $iTimezoneOffset = 0; if (isset($m[7])) { $oTz = new DateTimeZone($m[7]); $oUtc = new DateTime(str_replace($m[7], '', $mixedData), new DateTimeZone('UTC')); if ($oTz && $oUtc) $iTimezoneOffset = $oTz->getOffset($oUtc); } $sFunc = BX_DATA_DATETIME_TS_UTC == $iDataType ? 'gmmktime' : 'mktime'; $iRet = $sFunc ($iH, $iM, $iS, $iMonth, $iDay, $iYear) - $iTimezoneOffset; return $iRet > 0 ? $iRet : false; case BX_DATA_HTML: return clear_xss($mixedData); case BX_DATA_TEXT_MULTILINE: return nl2br(htmlspecialchars_adv($mixedData)); case BX_DATA_TEXT: default: return $mixedData; } } /* * Functions to process user output. * Always use this function before output data which was entered by user before. * @param $mixedData string to process * @param $iDataType how to handle data, possible valies the same as in bx_process_input function, see bx_process_input. * @param $mixedParams optional parameters to pass for validation * @return the filtered data, or FALSE if the filter fails. */ function bx_process_output ($mixedData, $iDataType = BX_DATA_TEXT, $mixedParams = false) { if (is_array($mixedData)) { foreach ($mixedData as $k => $v) $mixedData[$k] = bx_process_output($v, $iDataType, $mixedParams); return $mixedData; } switch ($iDataType) { case BX_DATA_INT: return filter_var($mixedData, FILTER_VALIDATE_INT); case BX_DATA_FLOAT: return filter_var($mixedData, FILTER_VALIDATE_FLOAT); case BX_DATA_CHECKBOX: return 'on' == trim($mixedData) ? 'on' : ''; case BX_DATA_DATE: case BX_DATA_DATETIME: return $mixedData; case BX_DATA_DATE_UTC: if (!preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $mixedData, $m)) return ''; return sprintf("%04d-%02d-%02d 00:00:00Z", $m[1], $m[2], $m[3]); return $mixedData . "Z"; case BX_DATA_DATETIME_UTC: return $mixedData . "Z"; case BX_DATA_DATE_TS: return empty($mixedData) ? '' : date("Y-m-d", (int)$mixedData); case BX_DATA_DATE_TS_UTC: return empty($mixedData) ? '' : gmdate("Y-m-d", (int)$mixedData); case BX_DATA_DATETIME_TS: return empty($mixedData) ? '' : date("Y-m-d H:i", (int)$mixedData); case BX_DATA_DATETIME_TS_UTC: return empty($mixedData) ? '' : gmdate("Y-m-d H:i:s\Z", (int)$mixedData); case BX_DATA_HTML: $s = bx_linkify_html($mixedData, 'class="' . BX_DOL_LINK_CLASS . '"'); // remove empty tags from html content: #4203, #4486, #4827, #4979 $s = preg_replace('/<(div|p|blockquote|pre|section|article)(?:\s[^>]*)?'.'>((?:\s|)*)<\/\1>/i', '', $s); $s = preg_replace('/(\s*){2,}/i', '
', $s); return $mixedParams && is_array($mixedParams) && in_array('no_process_macro', $mixedParams) ? $s : bx_process_macros($s); case BX_DATA_TEXT_MULTILINE: $s = $mixedData; return $mixedParams && is_array($mixedParams) && in_array('no_process_macros', $mixedParams) ? $s : bx_process_macros($s); case BX_DATA_TEXT: default: $s = htmlspecialchars_adv($mixedData); return $mixedParams && is_array($mixedParams) && in_array('no_process_macros', $mixedParams) ? $s : bx_process_macros($s); } } function bx_is_macros_in_content (&$s) { return false === strpos($s, '{{~') ? false : true; } /** * This function converts macros upon text output. * Macros represents constructions like this: * @code * {{!module_name:function[param1, "param2"]}} * @endcode * For example, to display some content from module Posts: * @code * {{!bx_posts:get_search_result_unit[3]}} * @endcode * Only users which have "use macros" ACL action enabled can use this functionlity. * * @param $s text to process * @return modified or not modified text */ function bx_process_macros ($s) { if (!bx_is_macros_in_content($s)) return $s; $aCode = []; $c = 1; $s = preg_replace_callback( "/()(.*?)(<\/code>)/s", function ($aMatches) use (&$c, &$aCode) { $aCode[$c] = $aMatches[2]; return $aMatches[1] . '___' . $c++ . '___' . $aMatches[3]; }, $s); $s = preg_replace_callback( "/{{\~(.*?)\~}}/", function ($aMatches) { return BxDolService::callMacro($aMatches[1]); }, $s); $s = preg_replace_callback( "/()___(.*?)___(<\/code>)/s", function ($aMatches) use (&$aCode) { $sCode = isset($aCode[$aMatches[2]]) ? $aCode[$aMatches[2]] : 'n/a'; return $aMatches[1] . $sCode . $aMatches[3]; }, $s); return $s; } /* * This function apply bx_process_input and then bx_process_output. * Use this function to output data immediately after receiving, without saving to database. * Patams are the same as bx_process_input function - @see bx_process_input */ function bx_process_pass ($mixedData, $iDataType = BX_DATA_TEXT, $mixedParams = false, $isCheckMagicQuotes = true) { return bx_process_output(bx_process_input ($mixedData, $iDataType, $mixedParams, $isCheckMagicQuotes), $iDataType, $mixedParams); } /** * DEPRECATED * use bx_process_input + bx_process_output instead * -------- * function for processing pass data * * This function cleans the GET/POST/COOKIE data if magic_quotes_gpc() is on * for data which should be outputed immediately after submit */ /* function process_pass_data( $text, $strip_tags = 0 ) { if ( $strip_tags ) $text = strip_tags($text); if ( !get_magic_quotes_gpc() ) return $text; else return stripslashes($text); } */ /* * function for output data from database into html */ function htmlspecialchars_adv( $string ) { return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false); } /** * Send mail to user by parsing email template */ function sendMailTemplate($sTemplateName, $iAccountId = 0, $iProfileId = 0, $aReplaceVars = array(), $iEmailType = BX_EMAIL_NOTIFY, $bAddToQueue = false) { $oProfile = $iProfileId ? BxDolProfile::getInstance($iProfileId) : null; $oAccount = $iAccountId ? BxDolAccount::getInstance($iAccountId) : ($oProfile ? $oProfile->getAccountObject() : null); $oEmailTemplates = BxDolEmailTemplates::getInstance(); if (!($oAccount || $oProfile) || !$oEmailTemplates) return false; $aTemplate = $oEmailTemplates->parseTemplate($sTemplateName, $aReplaceVars, $oAccount ? $oAccount->id() : 0, (int)$iProfileId); if (!$aTemplate) return false; return sendMail($oAccount->getEmail(), $aTemplate['Subject'], $aTemplate['Body'], 0, array(), $iEmailType, 'html', false, array(), $bAddToQueue); } /** * Send system email */ function sendMailTemplateSystem($sTemplateName, $aReplaceVars = array(), $iEmailType = BX_EMAIL_SYSTEM, $bAddToQueue = false) { $oEmailTemplates = BxDolEmailTemplates::getInstance(); if (!$oEmailTemplates) return false; $aTemplate = $oEmailTemplates->parseTemplate($sTemplateName, $aReplaceVars); if (!$aTemplate) return false; return sendMail(getParam('site_email'), $aTemplate['Subject'], $aTemplate['Body'], 0, array(), $iEmailType, 'html', false, array(), $bAddToQueue); } /** * Send email function * * @param $mRecipientEmails - Email where email should be send, can be array, string with one email or comma separated * @param $sMailSubject - subject of the message * @param $sMailBody - Body of the message * @param $iRecipientID - ID of recipient profile * @param $aPlus - Array of additional information * @param $iEmailType - email message type: BX_EMAIL_SYSTEM, BX_EMAIL_NOTIFY or BX_EMAIL_MASS * @param $sEmailFlag - use 'html' for HTML email message * @param $isDisableAlert - disable alert * @param $aCustomHeaders - custom email headers * @param $bAddToQueue - add message to email queue * @return true if message was send or false otherwise */ function sendMail($mRecipientEmails, $sMailSubject, $sMailBody, $iRecipientID = 0, $aPlus = array(), $iEmailType = BX_EMAIL_NOTIFY, $sEmailFlag = 'html', $isDisableAlert = false, $aCustomHeaders = array(), $bAddToQueue = false) { if (is_string($mRecipientEmails)){ if(strpos($mRecipientEmails, ',') !== false){ $mRecipientEmails = explode(',', $mRecipientEmails); } else{ return _sendMail($mRecipientEmails, $sMailSubject, $sMailBody, $iRecipientID, $aPlus, $iEmailType, $sEmailFlag, $isDisableAlert, $aCustomHeaders, $bAddToQueue); } } if (is_array($mRecipientEmails)) { $bReturn = false; foreach($mRecipientEmails as $sRecipientEmail) { $sRecipientEmail = trim($sRecipientEmail); if (_sendMail($sRecipientEmail, $sMailSubject, $sMailBody, $iRecipientID, $aPlus, $iEmailType, $sEmailFlag, $isDisableAlert, $aCustomHeaders, $bAddToQueue)) $bReturn = true; } return $bReturn; } } function _sendMail($sRecipientEmail, $sMailSubject, $sMailBody, $iRecipientID = 0, $aPlus = array(), $iEmailType = BX_EMAIL_NOTIFY, $sEmailFlag = 'html', $isDisableAlert = false, $aCustomHeaders = array(), $bAddToQueue = false) { // make sure that recipient's email is valid and message isn't empty if (!$sMailBody || !$sRecipientEmail || preg_match('/\(2\)$/', $sRecipientEmail)) return false; // get recipient account $oAccount = !$isDisableAlert ? BxDolAccount::getInstance($sRecipientEmail) : null; $aAccountInfo = $oAccount ? $oAccount->getInfo() : false; // don't send bulk emails if user didn't subscribed to site news or email is unconfirmed if ($aAccountInfo && BX_EMAIL_MASS == $iEmailType && (!$aAccountInfo['email_confirmed'] || !$aAccountInfo['receive_news'])) return false; // don't send email notifications if user didn't subscribed to notifications or email is unconfirmed if ($aAccountInfo && BX_EMAIL_NOTIFY == $iEmailType && (!$aAccountInfo['email_confirmed'] || !$aAccountInfo['receive_updates'])) return false; // decode HTML entities in the subj $sMailSubject = html_entity_decode($sMailSubject, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8'); if($bAddToQueue && BxDolQueueEmail::getInstance()->add($sRecipientEmail, $sMailSubject, $sMailBody, $iRecipientID, $aPlus, $iEmailType, $sEmailFlag, $isDisableAlert, $aCustomHeaders)) return true; // if profile id is provided - get profile's info $aRecipientInfo = false; if ($iRecipientID) { $oProfile = BxDolProfile::getInstance($iRecipientID); if ($oProfile) $aRecipientInfo = $oProfile->getInfo(); } // get site vars $sEmailNotify = !$isDisableAlert ? getParam('site_email_notify') : $sRecipientEmail; $sSiteTitle = !$isDisableAlert ? getParam('site_title') : 'UNA ' . BX_DOL_VERSION; // add unsubscribe link if (!$isDisableAlert && empty($aPlus['unsubscribe'])) { $aPlus['unsubscribe'] = ''; if ($oAccount && (BX_EMAIL_MASS == $iEmailType || BX_EMAIL_NOTIFY == $iEmailType)) $aPlus['unsubscribe'] = ($sLink = $oAccount->getUnsubscribeLink($iEmailType)) ? '' . _t('_sys_et_txt_unsubscribe') . '' : ''; } // parse template if ($aPlus || $iRecipientID || $oAccount) { if(!is_array($aPlus)) $aPlus = []; $oEmailTemplates = BxDolEmailTemplates::getInstance(); $sMailSubject = $oEmailTemplates->parseContent($sMailSubject, $aPlus, !$iRecipientID && $oAccount ? $oAccount->id() : 0, $iRecipientID); $sMailBody = $oEmailTemplates->parseContent($sMailBody, $aPlus, !$iRecipientID && $oAccount ? $oAccount->id() : 0, $iRecipientID); } if(($sRootUrl = getParam('sys_api_url_root_email')) !== '') { if(substr(BX_DOL_URL_ROOT, -1) == '/' && substr($sRootUrl, -1) != '/') $sRootUrl .= '/'; $sMailBody = str_replace(BX_DOL_URL_ROOT, $sRootUrl, $sMailBody); // restore URLs in images $sMailBody = str_replace([ 'src="' . $sRootUrl, "src='" . $sRootUrl ], [ 'src="' . BX_DOL_URL_ROOT, "src='" . BX_DOL_URL_ROOT ], $sMailBody); } // email message headers $sMailHeader = ''; foreach ($aCustomHeaders as $sHeaderName => $sHeaderValue) $sMailHeader = "$sHeaderName: $sHeaderValue\r\n" . $sMailHeader; if (!isset($aCustomHeaders['From'])) $sMailHeader = "From: =?UTF-8?B?" . base64_encode( $sSiteTitle ) . "?= <{$sEmailNotify}>"; if (!isset($aCustomHeaders['MIME-Version'])) $sMailHeader = "MIME-Version: 1.0\r\n" . $sMailHeader; $sMailParameters = isset($aCustomHeaders['Sender']) ? "-f{$aCustomHeaders['Sender']}" : "-f{$sEmailNotify}"; if (isset($aCustomHeaders['Subject'])) $sMailSubject = $aCustomHeaders['Subject']; // build data for alert handler $bResult = null; $aAlert = array( 'email' => $sRecipientEmail, 'subject' => $sMailSubject, 'body' => $sMailBody, 'header' => $sMailHeader, 'params' => $sMailParameters, 'recipient' => $aRecipientInfo, 'email_type' => $iEmailType, 'html' => 'html' == $sEmailFlag ? true : false, 'custom_headers' => $aCustomHeaders, 'override_result' => &$bResult, ); /** * @hooks * @hookdef hook-system-check_send_mail 'system', 'check_send_mail' - hook for disabling mail sending * - $unit_name - equals `system` * - $action - equals `check_send_mail` * - $object_id - recipient profile id * - $sender_id - not used * - $extra_params - array of additional params with the following array keys: * - `email` - [string] recipient email * - `subject` - [string] email subject * - `body` - [string] email body * - `header` - [string] email headers, headers are separated with double new line character * - `params` - [string] parameters for php mail function * - `recipient` - [array] recipient info array * - `email_type` - [int] email type, one of the following BX_EMAIL_SYSTEM, BX_EMAIL_NOTIFY, BX_EMAIL_MASS * - `html` - [boolean] `true` if email content is HTML, if `false` then email content is text * - `custom_headers` - [array] custom email headers array as key&value pairs * - `override_result` - [boolean] override result of `sendMail` function, if `true` then mail sending should continue as usual, if `false` then mail sending should stop * @hook @ref hook-system-check_send_mail */ bx_alert('system', 'check_send_mail', (isset($aRecipientInfo['ID']) ? $aRecipientInfo['ID'] : 0), '', $aAlert); if ($bResult !== null) return $bResult; // system alert if (!$isDisableAlert) { /** * @hooks * @hookdef hook-system-before_send_mail 'system', 'before_send_mail' - hook before mail sending * It's equivalent to @ref hook-system-check_send_mail * @hook @ref hook-system-before_send_mail */ bx_alert('system', 'before_send_mail', (isset($aRecipientInfo['ID']) ? $aRecipientInfo['ID'] : 0), '', $aAlert); if ($bResult !== null) return $bResult; unset($aAlert['override_result']); } // prepare HTML/Plain message if($sEmailFlag == 'html') $sMailHeader = "Content-type: text/html; charset=UTF-8\r\n" . $sMailHeader; else { $sMailHeader = "Content-type: text/plain; charset=UTF-8\r\n" . $sMailHeader; $sMailBody = html2txt($sMailBody); } // encode subject if (0 !== strncasecmp($sMailSubject, '=?UTF-8?B?', 10)) $sMailSubject = '=?UTF-8?B?' . base64_encode($sMailSubject) . '?='; // send mail or put it into queue $bResult = mail($sRecipientEmail, $sMailSubject, $sMailBody, $sMailHeader, $sMailParameters); // system alert if (!$isDisableAlert) { /** * @hooks * @hookdef hook-system-send_mail 'system', 'send_mail' - hook when mail was sent * It's equivalent to @ref hook-system-check_send_mail * except `override_result` parameter in $extra_params is missing * @hook @ref hook-system-send_mail */ bx_alert('system', 'send_mail', (isset($aRecipientInfo['ID']) ? $aRecipientInfo['ID'] : 0), '', $aAlert); } return $bResult; } /* * Getting an array with Templates' Names */ function get_templates_array($bEnabledOnly = true, $bShortInfo = true) { $oDb = BxDolDb::getInstance(); $sWhereAddon = $bEnabledOnly ? " AND `enabled`='1'" : ""; if($bShortInfo) return $oDb->getPairs("SELECT `uri`, `title` FROM `sys_modules` WHERE 1 AND `type`='" . BX_DOL_MODULE_TYPE_TEMPLATE . "'" . $sWhereAddon, "uri", "title"); else return $oDb->getAllWithKey("SELECT * FROM `sys_modules` WHERE 1 AND `type`='" . BX_DOL_MODULE_TYPE_TEMPLATE . "'" . $sWhereAddon, "uri"); } function bx_get_image_exif_and_size($oStorage, $oTranscoder, $iContentId){ $sData = ''; $sExif = ''; $aExif = false; $aPhoto = $oStorage->getFile($iContentId); if ($oTranscoder->isMimeTypeSupported($aPhoto['mime_type'])) { $oImageReize = BxDolImageResize::getInstance(); $a = $oImageReize->getImageSize($oTranscoder->getFileUrl($iContentId)); $sData = isset($a['w']) && isset($a['h']) ? $a['w'] . 'x' . $a['h'] : ''; if ($aExif = $oImageReize->getExifInfo($oStorage->getFileUrlById($iContentId))) { $a = array('Make', 'Model', 'FocalLength', 'ShutterSpeedValue', 'ExposureTime', 'ISOSpeedRatings', 'Orientation', 'Artist', 'Copyright', 'Flash', 'WhiteBalance', 'DateTimeOriginal', 'DateTimeDigitized', 'ExifVersion', 'COMPUTED', 'GPSLatitudeRef', 'GPSLatitude', 'GPSLongitudeRef', 'GPSLongitude', 'GPSAltitudeRef', 'GPSAltitude', 'GPSTimeStamp', 'GPSImgDirectionRef', 'GPSImgDirection', 'GPSDateStamp'); $aExifFiltered = array(); foreach ($a as $sIndex) if (isset($aExif[$sIndex])) $aExifFiltered[$sIndex] = $aExif[$sIndex]; $sExif = serialize($aExifFiltered); } } return array('exif' => $sExif, 'size' => $sData); } function bx_get_svg_image_size($sUrl) { $iWidth = $iHeight = 0; $sContent = bx_file_get_contents($sUrl); if(empty($sContent)) return [$iWidth, $iHeight]; $aAttributes = BxDolXmlParser::getInstance()->getAttributes($sContent, 'SVG', 0); if(isset($aAttributes['VIEWBOX'])) { $aViewBox = explode(' ', $aAttributes['VIEWBOX']); if(!empty($aViewBox) && is_array($aViewBox) && count($aViewBox) == 4) { $iWidth = (float)$aViewBox[2]; $iHeight = (float)$aViewBox[3]; } } if(!$iWidth && isset($aAttributes['WIDTH'])) $iWidth = (float)$aAttributes['WIDTH']; if(!$iHeight && isset($aAttributes['HEIGHT'])) $iHeight = (float)$aAttributes['HEIGHT']; return [$iWidth, $iHeight]; } function extFileExists( $sFileSrc ) { return (file_exists( $sFileSrc ) && is_file( $sFileSrc )) ? true : false; } function getVisitorIP() { $ip = "0.0.0.0"; if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (!isset( $_SERVER['HTTP_X_FORWARDED_FOR']) || empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { if (!isset( $_SERVER['HTTP_CLIENT_IP']) && empty($_SERVER['HTTP_CLIENT_IP']) && isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR']; } return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : "0.0.0.0"; } function genFlag($sLang = '', $oTemplate = null) { if (!$oTemplate) $oTemplate = BxDolTemplate::getInstance(); $oTemplate->addCss(BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'flag-icons/css/|flag-icons.min.css'); $sFlag = BxDolLanguages::getInstance()->getLangFlag($sLang); return ''; } // print debug information ( e.g. arrays ) function echoDbg( $what, $desc = '' ) { if ( $desc ) echo "$desc: "; echo "
";
        print_r( $what );
    echo "
\n"; } function echoDbgLog($mWhat, $sDesc = 'unused', $sFileName = 'unused') { bx_log('sys_debug', $mWhat, BX_LOG_DEBUG); } function bx_is_dbg() { return (defined('BX_DBG_COOKIE') && !empty($_COOKIE[BX_DBG_COOKIE])) || (defined('BX_DBG_PROFILES') && in_array(bx_get_logged_profile_id(), BX_DBG_PROFILES)); } function dbgTiming($sStartMicrotime) { $i1 = explode(' ', microtime ()); $i2 = explode(' ', $sStartMicrotime); $iTime = ($i1[0]+$i1[1]) - ($i2[0]+$i2[1]); return round($iTime, 6) . ' sec'; } function echoJson($a) { header('Content-Type: application/json; charset=utf-8'); echo json_encode($a); } function clear_xss($val) { // HTML Purifier plugin global $logged; global $oHtmlPurifier; $bAdmin = isset($logged) && $logged['admin']; if (!isset($oHtmlPurifier) && !$bAdmin) { HTMLPurifier_Bootstrap::registerAutoload(); $oConfig = HTMLPurifier_Config::createDefault(); $oConfig->set('Cache.SerializerPath', rtrim(BX_DIRECTORY_PATH_CACHE, '/')); $oConfig->set('Cache.SerializerPermissions', BX_DOL_DIR_RIGHTS); $oConfig->set('HTML.SafeObject', 'true'); $oConfig->set('Output.FlashCompat', 'true'); $oConfig->set('HTML.FlashAllowFullScreen', 'true'); $oConfig->set('Attr.AllowedFrameTargets', array('_blank', '_self', '_parent', '_top')); if (getParam('sys_add_nofollow')) { $sHost = parse_url(BX_DOL_URL_ROOT, PHP_URL_HOST); $oConfig->set('URI.Host', $sHost); $oConfig->set('HTML.Nofollow', 'true'); } $oConfig->set('Filter.Custom', array ( new BxDolHTMLPurifierFilterYouTube(), new BxDolHTMLPurifierFilterYoutubeIframe(), new BxDolHTMLPurifierFilterAddBxLinksClass(), new BxDolHTMLPurifierFilterLocalIframe(), new BxDolHTMLPurifierFilterEmbed(), )); $oConfig->set('HTML.DefinitionID', 'html5-definitions'); $oConfig->set('HTML.DefinitionRev', 1); if ($def = $oConfig->maybeGetRawHTMLDefinition()) { $def->addElement('section', 'Block', 'Flow', 'Common'); $def->addElement('nav', 'Block', 'Flow', 'Common'); $def->addElement('article', 'Block', 'Flow', 'Common'); $def->addElement('aside', 'Block', 'Flow', 'Common'); $def->addElement('header', 'Block', 'Flow', 'Common'); $def->addElement('footer', 'Block', 'Flow', 'Common'); $def->addElement('video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', array( 'src' => 'URI', 'type' => 'Text', 'width' => 'Length', 'height' => 'Length', 'poster' => 'URI', 'preload' => 'Enum#auto,metadata,none', 'controls' => 'Bool', )); $def->addElement('source', 'Block', 'Flow', 'Common', array( 'src' => 'URI', 'type' => 'Text', )); $def->addAttribute('a', 'data-profile-id', 'Text'); $def->addAttribute('a', 'dchar', 'Text'); $def->addAttribute('div', 'source', 'Text'); } $oHtmlPurifier = new HTMLPurifier($oConfig); } /** * Note. I'm not sure if double 'purify' is needed for non-admins. */ if(!$bAdmin) $val = $oHtmlPurifier->purify($val); $sNewVal = $val; if(!$bAdmin) $sNewVal = $oHtmlPurifier->purify($val); /** * @hooks * @hookdef hook-account-clear_xss 'account', 'clear_xss' - hook after string is checked for xss * - $unit_name - equals `system` * - $action - equals `clear_xss` * - $object_id - not used * - $sender_id - not used * - $extra_params - array of additional params with the following array keys: * - `oHtmlPurifier` - [object] HtmlPurifier object * - `input_data` - [string] string before check xss * - `return_data` - [string] by ref, string before check xss, can be overridden in hook processing * @hook @ref hook-system-clear_xss */ bx_alert('system', 'clear_xss', 0, 0, array('oHtmlPurifier' => $oHtmlPurifier, 'input_data' => $val, 'return_data' => &$sNewVal)); return $val; } //--------------------------------------- friendly permalinks --------------------------------------// //------------------------------------------- main functions ---------------------------------------// function uriGenerate ($sValue, $sTable, $sField, $aParams = []) { $sDivider = isset($aParams['divider']) ? $aParams['divider'] : '-'; $aCond = isset($aParams['cond']) && is_array($aParams['cond']) ? $aParams['cond'] : []; $sValue = uriFilter($sValue, $aParams); if(uriCheckUniq($sValue, $sTable, $sField, $aCond)) return $sValue; // cut off redundant part if(get_mb_len($sValue) > 240) $sValue = get_mb_substr($sValue, 0, 240); // try to add number for($i = 0 ; $i < 999 ; ++$i) { $iRnd = mt_rand(1000, 9999); if(uriCheckUniq($sValue . $sDivider . $iRnd, $sTable, $sField, $aCond)) return ($sValue . $sDivider . $iRnd); } return rand(0, PHP_INT_MAX); } function uriFilter ($s, $aParams = []) { $sEmpty = isset($aParams['empty']) ? $aParams['empty'] : '-'; $sDivider = isset($aParams['divider']) ? $aParams['divider'] : '-'; if(BxTemplConfig::getInstance()->bAllowUnicodeInPreg) $s = get_mb_replace ('/[^\pL^\pN^_]+/u', $sDivider, $s); // unicode characters else $s = get_mb_replace ('/([^\d^\w]+)/u', $sDivider, $s); // latin characters only $s = get_mb_replace ('/([' . $sDivider . '^]+)/', $sDivider, $s); $s = get_mb_replace ('/([' . $sDivider . ']+)$/', '', $s); // remove trailing dash if(!$s) $s = $sEmpty; return !isset($aParams['lowercase']) || $aParams['lowercase'] === true ? mb_strtolower($s) : $s; } function uriCheckUniq ($sValue, $sTable, $sField, $aCond = []) { $oDb = BxDolDb::getInstance(); $sWhere = $aCond ? $oDb->arrayToSQL($aCond, ' AND ') : '1'; $sSql = $oDb->prepare("SELECT 1 FROM `$sTable` WHERE $sWhere AND `$sField`=? LIMIT 1", $sValue); return !$oDb->query($sSql); } function get_mb_replace ($sPattern, $sReplace, $s) { return preg_replace ($sPattern, $sReplace, $s); } function get_mb_len ($s) { return (function_exists('mb_strlen')) ? mb_strlen($s) : strlen($s); } function get_mb_substr ($s, $iStart, $iLen) { return (function_exists('mb_substr')) ? mb_substr ($s, $iStart, $iLen) : substr ($s, $iStart, $iLen); } function bx_mb_substr_replace($s, $sReplace, $iPosStart, $iLength) { return mb_substr($s, 0, $iPosStart) . $sReplace . mb_substr($s, $iPosStart + $iLength); } function bx_mb_strpos ($s, $sReplacement, $iStart = 0) { return mb_strpos($s, $sReplacement, $iStart); } /** * Import class file, it automatically detects class path by its prefix or module array/name * * @param $sClassName - full class name or class postfix(withoit prefix) in the case of module class * @param $mixedModule - module array or module name in the case of module class */ function bx_import($sClassName, $mixedModule = array()) { if (class_exists($sClassName, false)) return; $aModule = false; if ($mixedModule) { if (is_array($mixedModule)) { $aModule = $mixedModule; } elseif (is_string($mixedModule)) { $o = BxDolModule::getInstance($mixedModule); $aModule = $o->_aModule; } elseif (is_bool($mixedModule) && true === $mixedModule) { $aModule = $GLOBALS['aModule']; } } if ($aModule) { if (class_exists($aModule['class_prefix'] . $sClassName, false)) return; require_once (BX_DIRECTORY_PATH_MODULES . $aModule['path'] . 'classes/' . $aModule['class_prefix'] . $sClassName . '.php'); return; } if (0 === strncmp($sClassName, 'BxDol', 5)) { if (0 === strncmp($sClassName, 'BxDolStudio', 11)) require_once(BX_DOL_DIR_STUDIO_CLASSES . $sClassName . '.php'); else require_once(BX_DIRECTORY_PATH_CLASSES . $sClassName . '.php'); return; } if (0 === strncmp($sClassName, 'BxBase', 6)) { if (0 === strncmp($sClassName, 'BxBaseMod', 9)) { $aMatches = array(); if (preg_match('/BxBaseMod([A-Z][a-z]+)/', $sClassName, $aMatches)) { require_once(BX_DIRECTORY_PATH_MODULES . 'base/' . strtolower($aMatches[1]) . '/classes/' . $sClassName . '.php'); return; } } if (0 === strncmp($sClassName, 'BxBaseStudio', 12)) { require_once(BX_DOL_DIR_STUDIO_BASE . 'scripts/' . $sClassName . '.php'); return; } else { require_once(BX_DIRECTORY_PATH_BASE . 'scripts/' . $sClassName . '.php'); return; } } if (0 === strncmp($sClassName, 'BxTempl', 7)) { if(0 === strncmp($sClassName, 'BxTemplStudio', 13)) { $sPath = BX_DIRECTORY_PATH_MODULES . BxDolStudioTemplate::getInstance()->getPath() . 'data/template/studio/scripts/' . $sClassName . '.php'; if (!file_exists($sPath)) $sPath = BX_DOL_DIR_STUDIO_BASE . 'scripts_templ/' . $sClassName . '.php'; } else { $sPath = BX_DIRECTORY_PATH_MODULES . BxDolTemplate::getInstance()->getPath() . 'data/template/system/scripts/' . $sClassName . '.php'; } if (file_exists($sPath)) { require_once($sPath); return; } else{ require_once(BX_DIRECTORY_PATH_BASE . 'scripts_templ/' . $sClassName . '.php'); return; } trigger_error ("bx_import fatal error: class (" . $sClassName . ") wasn't found", E_USER_ERROR); } } /** * used in spl_autoload_register() function, so no need to call bx_import for system classes */ function bx_autoload($sClassName) { if (0 === strncmp($sClassName, 'BxDol', 5) || 0 === strncmp($sClassName, 'BxBase', 6) || 0 === strncmp($sClassName, 'BxTempl', 7)) bx_import($sClassName); } /** * Gets an instance of class pathing necessary parameters if it's necessary. * * @param string $sClassName class name. * @param array $aParams an array of parameters to be pathed to the constructor of the class. * @param array $mixedModule an array with module description. Is used when the requested class is located in some module. * @return unknown */ function bx_instance($sClassName, $aParams = array(), $mixedModule = array()) { if(isset($GLOBALS['bxDolClasses'][$sClassName])) return $GLOBALS['bxDolClasses'][$sClassName]; if ($mixedModule) { if (!is_array($mixedModule)) { $o = BxDolModule::getInstance($mixedModule); $mixedModule = $o->_aModule; } $sClassName = bx_ltrim_str($sClassName, $mixedModule['class_prefix']); bx_import($sClassName, $mixedModule); $sClassName = $mixedModule['class_prefix'] . $sClassName; } $oClass = new ReflectionClass($sClassName); $GLOBALS['bxDolClasses'][$sClassName] = empty($aParams) ? $oClass->newInstance() : $oClass->newInstanceArgs($aParams); return $GLOBALS['bxDolClasses'][$sClassName]; } /** * Escapes string/array ready to pass to js script with filtered symbols like ', " etc * * @param $mixedInput - string/array which should be filtered * @param $iQuoteType - string escaping method: BX_ESCAPE_STR_AUTO(default), BX_ESCAPE_STR_APOS or BX_ESCAPE_STR_QUOTE * @return converted string / array */ function bx_js_string ($mixedInput, $iQuoteType = BX_ESCAPE_STR_AUTO) { $aUnits = array( "\n" => "\\n", "\r" => "", ); if (BX_ESCAPE_STR_APOS == $iQuoteType) { $aUnits["'"] = "\\'"; $aUnits[''] = ""; } elseif (BX_ESCAPE_STR_QUOTE == $iQuoteType) { $aUnits['"'] = '\\"'; $aUnits[''] = ''; } else { $aUnits['"'] = '"'; $aUnits["'"] = '''; $aUnits[""] = '</script>'; } return str_replace(array_keys($aUnits), array_values($aUnits), $mixedInput); } /** * Return input string/array ready to pass to html attribute with filtered symbols like ', " etc * * @param $mixedInput - string/array which should be filtered * @param $iQuoteType - string escaping BX_ESCAPE_STR_AUTO, BX_ESCAPE_STR_APOS or BX_ESCAPE_STR_QUOTE * @return converted string / array */ function bx_html_attribute ($mixedInput, $iQuoteType = BX_ESCAPE_STR_AUTO) { $aUnits = array (); if (BX_ESCAPE_STR_APOS == $iQuoteType) $aUnits["'"] = "\\'"; elseif (BX_ESCAPE_STR_QUOTE == $iQuoteType) $aUnits['"'] = '"'; else $aUnits = array("\"" => """, "'" => "'"); return str_replace(array_keys($aUnits), array_values($aUnits), $mixedInput); } /** * Escapes string/array ready to pass to php script with filtered symbols like ', " etc * * @param mixed $mixedInput - string/array which should be filtered * @return converted string / array */ function bx_php_string_apos ($mixedInput) { return str_replace("'", "\\'", $mixedInput); } function bx_php_string_quot ($mixedInput) { return str_replace('"', '\\"', $mixedInput); } /** * Gets file contents by URL. * * @param string $sFileUrl - file URL to be read. * @param array $aParams - an array of parameters to be pathed with URL. * @param string $sMethod - post or get. * @param array $aHeaders - custom headers. * @param string $sHttpCode - HTTP code to return * @param array $aBasicAuth - array with 'user' and 'password' for Basic HTTP Auth * @return string the file's contents. */ function bx_file_get_contents($sFileUrl, $aParams = array(), $sMethod = 'get', $aHeaders = array(), &$sHttpCode = null, $aBasicAuth = array(), $iTimeout = 0, $aCustomCurlParams = array()) { if(!in_array($sMethod, ['post', 'post-raw', 'post-json', 'post-json-object'])) $sFileUrl = bx_append_url_params($sFileUrl, $aParams); $sResult = ''; if(function_exists('curl_init')) { $rConnect = curl_init(); curl_setopt($rConnect, CURLOPT_USERAGENT, 'UNA ' . (defined('BX_DOL_VERSION') ? constant('BX_DOL_VERSION') : '')); curl_setopt($rConnect, CURLOPT_TIMEOUT, BxDolDb::getInstance() ? getParam('sys_default_curl_timeout') : 10); curl_setopt($rConnect, CURLOPT_URL, $sFileUrl); curl_setopt($rConnect, CURLOPT_RETURNTRANSFER, 1); if (0 !== $iTimeout) { curl_setopt($rConnect, CURLOPT_CONNECTTIMEOUT, $iTimeout); curl_setopt($rConnect, CURLOPT_TIMEOUT, $iTimeout); } if(getParam('sys_curl_ssl_allow_untrusted') == 'on'){ curl_setopt($rConnect, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($rConnect, CURLOPT_SSL_VERIFYHOST, false); } if (!ini_get('open_basedir')) curl_setopt($rConnect, CURLOPT_FOLLOWLOCATION, 1); if ($aBasicAuth) curl_setopt($rConnect, CURLOPT_USERPWD, $aBasicAuth['user'] . ':' . $aBasicAuth['password']); if ('post' == $sMethod) { curl_setopt($rConnect, CURLOPT_POST, true); curl_setopt($rConnect, CURLOPT_POSTFIELDS, http_build_query($aParams)); } elseif ('post-raw' == $sMethod) { curl_setopt($rConnect, CURLOPT_POST, true); curl_setopt($rConnect, CURLOPT_POSTFIELDS, $aParams); } elseif ('post-json' == $sMethod) { curl_setopt($rConnect, CURLOPT_POST, true); curl_setopt($rConnect, CURLOPT_POSTFIELDS, json_encode($aParams)); $aHeaders[] = 'Content-Type: application/json'; } elseif ('post-json-object' == $sMethod) { curl_setopt($rConnect, CURLOPT_POST, true); curl_setopt($rConnect, CURLOPT_POSTFIELDS, json_encode($aParams, JSON_FORCE_OBJECT)); $aHeaders[] = 'Content-Type: application/json'; } elseif ($sMethod != 'get') { curl_setopt($rConnect, CURLOPT_CUSTOMREQUEST, $sMethod); } if ($aHeaders) curl_setopt($rConnect, CURLOPT_HTTPHEADER, $aHeaders); if (defined('BX_DOL_URL_ROOT') && 0 === strpos($sFileUrl, BX_DOL_URL_ROOT)) { curl_setopt($rConnect, CURLOPT_COOKIE, http_build_query($_COOKIE, '', '; ', PHP_QUERY_RFC3986)); } if ($aCustomCurlParams) foreach ($aCustomCurlParams as $sName => $mixedValue) curl_setopt($rConnect, $sName, $mixedValue); $sResult = curl_exec($rConnect); if (curl_errno($rConnect) == 60) { // CURLE_SSL_CACERT curl_setopt($rConnect, CURLOPT_CAINFO, BX_DIRECTORY_PATH_PLUGINS . 'curl/cacert/cacert.pem'); $sResult = curl_exec($rConnect); } if (NULL !== $sHttpCode) $sHttpCode = curl_getinfo($rConnect, CURLINFO_HTTP_CODE); } else { $iSaveTimeout = false; if (0 !== $iTimeout) { $iSaveTimeout = ini_get('default_socket_timeout'); ini_set('default_socket_timeout', $iTimeout); } $sResult = @file_get_contents($sFileUrl); if (0 !== $iTimeout && false !== $iSaveTimeout) { ini_set('default_socket_timeout', $iSaveTimeout); } } return $sResult; } function bx_make_utf8($s) { // Test it and see if it is UTF-8 or not if (false !== mb_detect_encoding($s, ["UTF-8"], true)) return $s; $sEncoding = mb_detect_encoding($s, ['ASCII', 'BASE64', 'HTML-ENTITIES', 'Windows-1251', 'KOI8-R'], true); if ($sEncoding === false) return $s; return mb_convert_encoding($s, "UTF-8", $sEncoding); } function bx_get_site_info($sSourceUrl, $aProcessAdditionalTags = array()) { $aResult = array(); $sContent = bx_file_get_contents($sSourceUrl); if ($sContent) { $sCharset = ''; preg_match("//i", $sContent, $aMatch); if (isset($aMatch[1])) $sCharset = $aMatch[1]; $sContent = preg_replace("/]*>(.*?)<\/script>/i", '', $sContent); $sContent = preg_replace("/]*>(.*?)<\/style>/i", '', $sContent); if (preg_match("/]*>(.*?)<\/title>/i", $sContent, $aMatch)) $aResult['title'] = bx_make_utf8(strip_tags($aMatch[1]), $sCharset); else $aResult['title'] = parse_url($sSourceUrl, PHP_URL_HOST); $aResult['description'] = bx_make_utf8(bx_parse_html_tag($sContent, 'meta', 'name', 'description', 'content', $sCharset), $sCharset); $aResult['keywords'] = bx_make_utf8(bx_parse_html_tag($sContent, 'meta', 'name', 'keywords', 'content', $sCharset), $sCharset); if ($aProcessAdditionalTags) { foreach ($aProcessAdditionalTags as $k => $a) { $aResult[$k] = bx_parse_html_tag( $sContent, isset($a['tag']) ? $a['tag'] : 'meta', isset($a['name_attr']) ? $a['name_attr'] : 'itemprop', isset($a['name']) ? $a['name'] : $k, isset($a['content_attr']) ? $a['content_attr'] : 'content', $sCharset, isset($a['specialchars_decode']) ? $a['specialchars_decode'] : true); if ((isset($a['name']) && 'og:image' == $a['name']) || (isset($a['tag']) && 'link' == $a['tag'])) { $aResult[$k] = bx_get_site_info_fix_relative_url ($sSourceUrl, $aResult[$k]); } } } } return $aResult; } /** * Fix relative URL to make it absolute * @param $sSourceUrl main URL * @param $s URL to fix * @return absolute URL or URL wothout changes */ function bx_get_site_info_fix_relative_url ($sSourceUrl, $s) { if (0 === stripos($s, 'http://') || 0 === stripos($s, 'https://') || 0 === stripos($s, 'ftp://') || !$s) return $s; if ('/' == $s[0]) { $a = parse_url($sSourceUrl); return $a['scheme'] . '://' . $a['host'] . (empty($a['port']) || 80 == $a['port'] || 443 == $a['port'] ? '' : ':' . $a['port']) . $s; } return $sSourceUrl . ('/' === substr($sSourceUrl, -1) ? $s : '/' . $s); } function bx_parse_html_tag ($sContent, $sTag, $sAttrNameName, $sAttrNameValue, $sAttrContentName, $sCharset = false, $bSpecialCharsDecode = true) { // This regex is designed to be more flexible with attribute orders and spacing $regex = "/<{$sTag}\s+(?:[^>]*?\s+)?{$sAttrNameName}\s*=\s*['\"]?{$sAttrNameValue}['\"]?\s+[^>]*{$sAttrContentName}\s*=\s*['\"]([^'\"]*)['\"][^>]*>/i"; if (!preg_match($regex, $sContent, $aMatch)) { // Try reversing the attribute order in case the first regex fails $regex = "/<{$sTag}\s+(?:[^>]*?\s+)?{$sAttrContentName}\s*=\s*['\"]([^'\"]*)['\"]\s+[^>]*{$sAttrNameName}\s*=\s*['\"]?{$sAttrNameValue}['\"]?[^>]*>/i"; preg_match($regex, $sContent, $aMatch); } // Extract the attribute content if available $s = isset($aMatch[1]) ? $aMatch[1] : ''; // Optionally convert character encoding if ($s && $sCharset) { $s = mb_convert_encoding($s, 'UTF-8', $sCharset); } // Optionally decode special HTML characters if ($bSpecialCharsDecode) { $s = htmlspecialchars_decode($s); } return $s; } // calculation ini_get('upload_max_filesize') in bytes as example function return_bytes($val) { $val = trim($val); $last = strtolower($val[strlen($val)-1]); $val = (int)$val; switch($last) { // The 'G' modifier is available since PHP 5.1.0 case 'k': $val *= 1024; break; case 'm': $val *= 1024 * 1024; break; case 'g': $val *= 1024 * 1024 * 1024; break; } return $val; } /** * Format bytes to human-readable format * @param $iBytes - number of bytes * @param $iPrecision - decimal places (default 1) * @return formatted string like "2.5M", "512K", "1024B" */ function bx_format_bytes($iBytes) { return _t_format_size($iBytes); } // Generate Random Password function genRndPwd($iLength = 8, $bSpecialCharacters = true) { $sPassword = ''; $sChars = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; if($bSpecialCharacters === true) $sChars .= "!?=/&+,."; for($i = 0; $i < $iLength; $i++) { $x = mt_rand(0, strlen($sChars) -1); $sPassword .= $sChars[$x]; } return $sPassword; } // Generate Random Salt for Password encryption function genRndSalt() { return genRndPwd(8, true); } function bx_gen_secret($sV) { $iL = strlen($sV); $iV = ceil(0.1 * $iL); return substr($sV, 0, $iV) . str_repeat('*', floor(0.8 * $iL)) . substr($sV, -$iV); } /** * Encrypt user password. * When BX_PWD_ALGO is 'custom', then bx_custom_pwd_encrypt function with custom algorythm must be defined in inc/header.inc.php file. * @param $sPwd clear password * @param $sSalt salt * @return password hash */ function encryptUserPwd($sPwd, $sSalt) { $sAlgo = defined('BX_PWD_ALGO') ? BX_PWD_ALGO : ''; switch ($sAlgo) { case 'custom': return bx_custom_pwd_encrypt($sPwd, $sSalt); case 'crypt': return crypt($sPwd, BX_PWD_ALGO_SALT); case 'sha1_crypt_salt': return sha1(crypt($sPwd, BX_PWD_ALGO_SALT) . $sSalt); case 'sha1_md5_salt': default: return sha1(md5($sPwd) . $sSalt); } } /** * Hash profile ID */ function encryptUserId($sId) { if (!($oProfile = BxDolProfile::getInstance($sId))) return false; if (!($oAccount = $oProfile->getAccountObject())) return false; $aAccountInfo = $oAccount->getInfo(); return sha1(md5($sId) . md5($aAccountInfo['salt']) . BX_DOL_SECRET); } function bx_get_reset_password_key($sValue, $sField = 'email', $iLifetime = 0) { if(empty($iLifetime)) { $iLifetime = (int)getParam('sys_account_reset_password_key_lifetime'); if(empty($iLifetime)) $iLifetime = 86400; } $oKey = BxDolKey::getInstance(); if(!$oKey) return false; return $oKey->getNewKey(array($sField => $sValue), $iLifetime); } function bx_get_reset_password_link($sValue, $sField = 'email', $iLifetime = 0) { $sKey = bx_get_reset_password_key($sValue, $sField, $iLifetime); if(!$sKey) return false; return bx_get_reset_password_link_by_key($sKey); } function bx_get_reset_password_link_by_key($sKey) { return bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=forgot-password', array('key' => $sKey))); } function bx_get_reset_password_redirect($iAccountId) { $sResult = ''; $sRedirect = getParam('sys_account_reset_password_redirect'); switch($sRedirect) { case 'home': $sResult = BxDolPermalinks::getInstance()->permalink('page.php?i=home'); break; case 'profile': case 'profile_edit': if(empty($iAccountId)) break; $oAccount = BxDolAccount::getInstance($iAccountId); if(!$oAccount) break; $aAccountInfo = $oAccount->getInfo(); if(empty($aAccountInfo) || !is_array($aAccountInfo) || empty($aAccountInfo['profile_id'])) break; $oProfile = BxDolProfile::getInstance((int)$aAccountInfo['profile_id']); if(!$oProfile) break; $sResult = $oProfile->{'get' . ($sRedirect == 'profile_edit' ? 'Edit' : '') . 'Url'}(); break; case 'custom': $sResult = getParam('sys_account_reset_password_redirect_custom'); break; } if(!empty($sResult)) $sResult = bx_absolute_url($sResult); return $sResult; } function bx_get ($sName, $sMethod = false) { if (isset($_GET[$sName]) && ('get' == $sMethod || !$sMethod)) return $_GET[$sName]; elseif (isset($_POST[$sName]) && ('post' == $sMethod || !$sMethod)) return $_POST[$sName]; else return false; } function bx_set ($sName, $sValue, $sMethod = false) { if(!$sMethod) $sMethod = 'get'; $bResult = true; switch($sMethod) { case 'get': $_GET[$sName] = $sValue; break; case 'post': $_POST[$sName] = $sValue; break; default: $bResult = false; } return $bResult; } function bx_get_with_prefix ($sPrefix, $sMethod = false) { $aSources = array('get' => &$_GET, 'post' => &$_POST); $aFiltered = array(); foreach($aSources as $sName => $aSource) if($sMethod == $sName || !$sMethod) $aFiltered = array_merge($aFiltered, array_filter($aSource, function($sKey) use ($sPrefix) { return strpos($sKey, $sPrefix) === 0; }, ARRAY_FILTER_USE_KEY)); $aUpdated = array(); array_walk($aFiltered, function($sValue, $sKey) use ($sPrefix, &$aUpdated) { $aUpdated[trim(str_replace($sPrefix, '', $sKey), '_-')] = $sValue; }); return $aUpdated; } function bx_get_base_url_inline($aParams = array()) { $aBaseLink = parse_url(BX_DOL_URL_ROOT); $sPageLink = (!empty($aBaseLink['scheme']) ? $aBaseLink['scheme'] : 'http') . '://' . $aBaseLink['host'] . (!empty($aBaseLink['port']) ? ':' . $aBaseLink['port'] : ''); if(!empty($_SERVER['REQUEST_URI'])) $sPageLink .= $_SERVER['REQUEST_URI']; list($sPageLink, $aPageParams) = bx_get_base_url($sPageLink); if(!empty($_SERVER['QUERY_STRING'])) { $aPageParamsAdd = array(); parse_str($_SERVER['QUERY_STRING'], $aPageParamsAdd); if(!empty($aPageParamsAdd) && is_array($aPageParamsAdd)) $aPageParams = array_merge($aPageParams, $aPageParamsAdd); } if(!empty($aParams) && is_array($aParams)) $aPageParams = array_merge($aPageParams, $aParams); return array($sPageLink, $aPageParams); } function bx_get_base_url_popup($aParams = array()) { list($sPageLink, $aPageParams) = bx_get_base_url($_SERVER['HTTP_REFERER']); if(!empty($aParams) && is_array($aParams)) $aPageParams = array_merge($aPageParams, $aParams); return array($sPageLink, $aPageParams); } function bx_get_base_url($sPageLink) { $sPageLink = BxDolPermalinks::getInstance()->unpermalink($sPageLink, false); $sPageParams = ''; if(strpos($sPageLink, '?') !== false) list($sPageLink, $sPageParams) = explode('?', $sPageLink); $aPageParams = array(); if(!empty($sPageParams)) parse_str($sPageParams, $aPageParams); return array($sPageLink, $aPageParams); } function bx_get_page_info() { list($sPageLink, $aPageParams) = bx_get_base_url_inline(); if(isset($aPageParams['i'], $aPageParams['id']) && ($oPage = BxDolPage::getObjectInstanceByURI($aPageParams['i'])) !== false) { $sPageModule = $oPage->getModule(); if(bx_srv('system', 'is_module_context', [$sPageModule]) && ($oProfile = BxDolProfile::getInstanceByContentAndType($aPageParams['id'], $sPageModule)) !== false) return [ 'context_module' => $sPageModule, 'context_id' => $aPageParams['id'], 'context_profile_id' => $oProfile->id() ]; } if(isset($aPageParams['profile_id']) && ($oProfile = BxDolProfile::getInstance($aPageParams['profile_id'])) !== false) { $sProfileModule = $oProfile->getModule(); if(bx_srv('system', 'is_module_context', [$sProfileModule])) return [ 'context_module' => $sProfileModule, 'context_id' => $oProfile->getContentId(), 'context_profile_id' => $aPageParams['profile_id'] ]; } return false; } function bx_get_location_bounds_latlng($fLatitude, $fLongitude, $iRadiusInKm) { $fEquatorLatInKm = 111.321; $aRv = array(); $aRv['max_lat'] = $fLatitude + $iRadiusInKm / $fEquatorLatInKm; $aRv['min_lat'] = $fLatitude - ($aRv['max_lat'] - $fLatitude); $aRv['max_lng'] = $fLongitude + $iRadiusInKm / (cos($aRv['min_lat'] * M_PI / 180) * $fEquatorLatInKm); $aRv['min_lng'] = $fLongitude - ($aRv['max_lng'] - $fLongitude); return $aRv; } function bx_encode_url_params ($a, $aExcludeKeys = array (), $aOnlyKeys = false) { $s = ''; foreach ($a as $sKey => $sVal) { if (in_array($sKey, $aExcludeKeys)) continue; if (false !== $aOnlyKeys && !in_array($sKey, $aOnlyKeys)) continue; if (is_array($sVal)) { foreach ($sVal as $sSubVal) { $s .= rawurlencode($sKey) . '[]=' . rawurlencode(is_array($sSubVal) ? 'array' : $sSubVal) . '&'; } } else { $s .= rawurlencode($sKey) . '=' . rawurlencode($sVal) . '&'; } } return $s; } /** * It works similar to `parse_str` php function, but it doesn't decode URL params */ function bx_parse_str($s) { $a = []; $aPairs = explode('&', $s); foreach ($aPairs as $i) { list($sName, $mixedValue) = explode('=', $i, 2); $sName = rtrim($sName, '[]'); if (isset($a[$sName])) { if (is_array($a[$sName])) $a[$sName][] = $mixedValue; else $a[$sName] = [$a[$sName], $mixedValue]; } else { $a[$sName] = $mixedValue; } } return $a; } function bx_append_url_params ($sUrl, $mixedParams, $bEncodeParams = true, $aIgnoreParams = []) { if (!$mixedParams) return $sUrl; $sParams = false === strpos($sUrl, '?') ? '?' : '&'; if (is_array($mixedParams)) { foreach($mixedParams as $sKey => $sValue) { if (!is_array($sValue)) { if ($bEncodeParams) { if ($sKey && !in_array($sKey, $aIgnoreParams)) $sKey = rawurlencode($sKey); if ($sValue && !in_array($sValue, $aIgnoreParams)) $sValue = rawurlencode($sValue); } $sParams .= $sKey . '=' . $sValue . '&'; } else { foreach($sValue as $sSubValue) { if ($bEncodeParams) { if ($sKey && !in_array($sKey, $aIgnoreParams)) $sKey = rawurlencode($sKey); if ($sSubValue && !in_array($sSubValue, $aIgnoreParams)) $sSubValue = rawurlencode($sSubValue); } $sParams .= $sKey . '[]=' . $sSubValue . '&'; } } } $sParams = substr($sParams, 0, -1); } else { $sParams .= $mixedParams; } return $sUrl . $sParams; } function bx_process_url_param($sValue, $sPattern = "/^[\d\w_-]+$/") { $mixedValue = bx_process_input($sValue); return $mixedValue !== false && preg_match($sPattern, $mixedValue) ? $mixedValue : ''; } function bx_rrmdir($directory) { if (substr($directory,-1) == "/") $directory = substr($directory,0,-1); if (!file_exists($directory) || !is_dir($directory)) return false; elseif (!is_readable($directory)) return false; if (!($directoryHandle = opendir($directory))) return false; while ($contents = readdir($directoryHandle)) { if ($contents != '.' && $contents != '..') { $path = $directory . "/" . $contents; if (is_dir($path)) bx_rrmdir($path); else unlink($path); } } closedir($directoryHandle); if (!rmdir($directory)) return false; return true; } function bx_clear_folder ($sPath, $aExts = array ()) { if (substr($$sPath,-1) == "/") $sPath = substr($sPath,0,-1); if (!file_exists($sPath) || !is_dir($sPath)) return false; elseif (!is_readable($sPath)) return false; if (!($h = opendir($sPath))) return false; while ($sFile = readdir($h)) { if ('.' == $sFile || '..' == $sFile) continue; $sFullPath = $sPath . '/' . $sFile; if (is_dir($sFullPath)) continue; if (!$aExts || (($sExt = pathinfo($sFullPath, PATHINFO_EXTENSION)) && in_array($sExt, $aExts))) @unlink($sFullPath); } closedir($h); return true; } function bx_ltrim_str ($sString, $sPrefix, $sReplace = '') { if ($sReplace && substr($sString, 0, strlen($sReplace)) == $sReplace) return $sString; if (substr($sString, 0, strlen($sPrefix)) == $sPrefix) return $sReplace . substr($sString, strlen($sPrefix)); return $sString; } function bx_rtrim_str ($sString, $sPrefix, $sReplace = '') { if ($sReplace && substr($sString, -strlen($sReplace)) == $sReplace) return $sString; if (substr($sString, -strlen($sPrefix)) == $sPrefix) return substr($sString, 0, -strlen($sPrefix)) . $sReplace; return $sString; } /** * Strip all lines with no information for example:

,

*/ function bx_trim_nl_duplicates($s) { $sStrip = implode('', array_keys(get_html_translation_table(HTML_ENTITIES))); return implode('', array_filter(mb_split("[\n\r]", $s), function($s) use ($sStrip) { return trim(strip_tags($s, '