本文整理汇总了PHP中Util::strlen方法的典型用法代码示例。如果您正苦于以下问题:PHP Util::strlen方法的具体用法?PHP Util::strlen怎么用?PHP Util::strlen使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Util
的用法示例。
在下文中一共展示了Util::strlen方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的PHP代码示例。
示例1: isValidEmail
/**
* A very simple function to determine if an email address is "valid" for Elkarte.
* A valid email for ElkArte is something that resebles an email (filter_var) and
* is less than 255 characters (for database limits)
*
* @param string $value - The string to evaluate as valid email
* @return bool|string - The email if valid, false if not a valid email
*/
function isValidEmail($value)
{
$value = trim($value);
if (filter_var($value, FILTER_VALIDATE_EMAIL) && Util::strlen($value) < 255) {
return $value;
} else {
return false;
}
}
示例2: ssi_recentTopics
/**
* Recent topic list:
* [board] Subject by Poster Date
*
* @param int $num_recent
* @param int[]|null $exclude_boards
* @param bool|null $include_boards
* @param string $output_method = 'echo'
*/
function ssi_recentTopics($num_recent = 8, $exclude_boards = null, $include_boards = null, $output_method = 'echo')
{
global $settings, $scripturl, $txt, $user_info, $modSettings;
$db = database();
if ($exclude_boards === null && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0) {
$exclude_boards = array($modSettings['recycle_board']);
} else {
$exclude_boards = empty($exclude_boards) ? array() : (is_array($exclude_boards) ? $exclude_boards : array($exclude_boards));
}
// Only some boards?.
if (is_array($include_boards) || (int) $include_boards === $include_boards) {
$include_boards = is_array($include_boards) ? $include_boards : array($include_boards);
} elseif ($include_boards != null) {
$output_method = $include_boards;
$include_boards = array();
}
require_once SUBSDIR . '/MessageIndex.subs.php';
$icon_sources = MessageTopicIcons();
// Find all the posts in distinct topics. Newer ones will have higher IDs.
$request = $db->query('', '
SELECT
t.id_topic, b.id_board, b.name AS board_name
FROM {db_prefix}topics AS t
INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
WHERE t.id_last_msg >= {int:min_message_id}' . (empty($exclude_boards) ? '' : '
AND b.id_board NOT IN ({array_int:exclude_boards})') . '' . (empty($include_boards) ? '' : '
AND b.id_board IN ({array_int:include_boards})') . '
AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? '
AND t.approved = {int:is_approved}
AND ml.approved = {int:is_approved}' : '') . '
ORDER BY t.id_last_msg DESC
LIMIT ' . $num_recent, array('include_boards' => empty($include_boards) ? '' : $include_boards, 'exclude_boards' => empty($exclude_boards) ? '' : $exclude_boards, 'min_message_id' => $modSettings['maxMsgID'] - 35 * min($num_recent, 5), 'is_approved' => 1));
$topics = array();
while ($row = $db->fetch_assoc($request)) {
$topics[$row['id_topic']] = $row;
}
$db->free_result($request);
// Did we find anything? If not, bail.
if (empty($topics)) {
return array();
}
// Find all the posts in distinct topics. Newer ones will have higher IDs.
$request = $db->query('substring', '
SELECT
mf.poster_time, mf.subject, ml.id_topic, mf.id_member, ml.id_msg, t.num_replies, t.num_views, mg.online_color,
IFNULL(mem.real_name, mf.poster_name) AS poster_name, ' . ($user_info['is_guest'] ? '1 AS is_read, 0 AS new_from' : '
IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) >= ml.id_msg_modified AS is_read,
IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from') . ', SUBSTRING(mf.body, 1, 384) AS body, mf.smileys_enabled, mf.icon
FROM {db_prefix}topics AS t
INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_last_msg)
LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = mf.id_member)' . (!$user_info['is_guest'] ? '
LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})' : '') . '
LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = mem.id_group)
WHERE t.id_topic IN ({array_int:topic_list})', array('current_member' => $user_info['id'], 'topic_list' => array_keys($topics)));
$posts = array();
while ($row = $db->fetch_assoc($request)) {
$row['body'] = strip_tags(strtr(parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']), array('<br />' => ' ')));
if (Util::strlen($row['body']) > 128) {
$row['body'] = Util::substr($row['body'], 0, 128) . '...';
}
// Censor the subject.
censorText($row['subject']);
censorText($row['body']);
if (!empty($modSettings['messageIconChecks_enable']) && !isset($icon_sources[$row['icon']])) {
$icon_sources[$row['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['icon'] . '.png') ? 'images_url' : 'default_images_url';
}
// Build the array.
$posts[] = array('board' => array('id' => $topics[$row['id_topic']]['id_board'], 'name' => $topics[$row['id_topic']]['board_name'], 'href' => $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0">' . $topics[$row['id_topic']]['board_name'] . '</a>'), 'topic' => $row['id_topic'], 'poster' => array('id' => $row['id_member'], 'name' => $row['poster_name'], 'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>'), 'subject' => $row['subject'], 'replies' => $row['num_replies'], 'views' => $row['num_views'], 'short_subject' => Util::shorten_text($row['subject'], 25), 'preview' => $row['body'], 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';topicseen#new', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#new" rel="nofollow">' . $row['subject'] . '</a>', 'new' => !empty($row['is_read']), 'is_new' => empty($row['is_read']), 'new_from' => $row['new_from'], 'icon' => '<img src="' . $settings[$icon_sources[$row['icon']]] . '/post/' . $row['icon'] . '.png" style="vertical-align: middle;" alt="' . $row['icon'] . '" />');
}
$db->free_result($request);
// Just return it.
if ($output_method != 'echo' || empty($posts)) {
return $posts;
}
echo '
<table class="ssi_table">';
foreach ($posts as $post) {
echo '
<tr>
<td class="righttext top">
[', $post['board']['link'], ']
</td>
<td class="top">
<a href="', $post['href'], '">', $post['subject'], '</a>
', $txt['by'], ' ', $post['poster']['link'], '
', !$post['is_new'] ? '' : '<a href="' . $scripturl . '?topic=' . $post['topic'] . '.msg' . $post['new_from'] . ';topicseen#new" rel="nofollow"><span class="new_posts">' . $txt['new'] . '</span></a>', '
</td>
<td class="righttext">
//.........这里部分代码省略.........
示例3: validateEventPost
/**
* Makes sure the calendar post is valid.
*
* @package Calendar
*/
function validateEventPost()
{
global $modSettings;
if (!isset($_POST['deleteevent'])) {
// No month? No year?
if (!isset($_POST['month'])) {
fatal_lang_error('event_month_missing', false);
}
if (!isset($_POST['year'])) {
fatal_lang_error('event_year_missing', false);
}
// Check the month and year...
if ($_POST['month'] < 1 || $_POST['month'] > 12) {
fatal_lang_error('invalid_month', false);
}
if ($_POST['year'] < $modSettings['cal_minyear'] || $_POST['year'] > $modSettings['cal_maxyear']) {
fatal_lang_error('invalid_year', false);
}
}
// Make sure they're allowed to post...
isAllowedTo('calendar_post');
if (isset($_POST['span'])) {
// Make sure it's turned on and not some fool trying to trick it.
if (empty($modSettings['cal_allowspan'])) {
fatal_lang_error('no_span', false);
}
if ($_POST['span'] < 1 || $_POST['span'] > $modSettings['cal_maxspan']) {
fatal_lang_error('invalid_days_numb', false);
}
}
// There is no need to validate the following values if we are just deleting the event.
if (!isset($_POST['deleteevent'])) {
// No day?
if (!isset($_POST['day'])) {
fatal_lang_error('event_day_missing', false);
}
if (!isset($_POST['evtitle']) && !isset($_POST['subject'])) {
fatal_lang_error('event_title_missing', false);
} elseif (!isset($_POST['evtitle'])) {
$_POST['evtitle'] = $_POST['subject'];
}
// Bad day?
if (!checkdate($_POST['month'], $_POST['day'], $_POST['year'])) {
fatal_lang_error('invalid_date', false);
}
// No title?
if (Util::htmltrim($_POST['evtitle']) === '') {
fatal_lang_error('no_event_title', false);
}
if (Util::strlen($_POST['evtitle']) > 100) {
$_POST['evtitle'] = Util::substr($_POST['evtitle'], 0, 100);
}
$_POST['evtitle'] = str_replace(';', '', $_POST['evtitle']);
}
}
示例4: splitTopic
//.........这里部分代码省略.........
LIMIT 2', array('msg_list' => $splitMessages, 'id_topic' => $split1_ID_TOPIC));
while ($row = $db->fetch_assoc($request)) {
// As before get the right first and last message dependant on approved state...
if (empty($split2_first_msg) || $row['myid_first_msg'] < $split2_first_msg) {
$split2_first_msg = $row['myid_first_msg'];
}
if (empty($split2_last_msg) || $row['approved']) {
$split2_last_msg = $row['myid_last_msg'];
}
// Then do the counts again...
if ($row['approved']) {
$split2_approved = true;
$split2_replies = $row['message_count'] - 1;
$split2_unapprovedposts = 0;
} else {
// Should this one be approved??
if ($split2_first_msg == $row['myid_first_msg']) {
$split2_approved = false;
}
if (!isset($split2_replies)) {
$split2_replies = 0;
} elseif (!$split2_approved) {
$split2_replies++;
}
$split2_unapprovedposts = $row['message_count'];
}
}
$db->free_result($request);
$split2_firstMem = getMsgMemberID($split2_first_msg);
$split2_lastMem = getMsgMemberID($split2_last_msg);
// No database changes yet, so let's double check to see if everything makes at least a little sense.
if ($split1_first_msg <= 0 || $split1_last_msg <= 0 || $split2_first_msg <= 0 || $split2_last_msg <= 0 || $split1_replies < 0 || $split2_replies < 0 || $split1_unapprovedposts < 0 || $split2_unapprovedposts < 0 || !isset($split1_approved) || !isset($split2_approved)) {
fatal_lang_error('cant_find_messages');
}
// You cannot split off the first message of a topic.
if ($split1_first_msg > $split2_first_msg) {
fatal_lang_error('split_first_post', false);
}
// We're off to insert the new topic! Use 0 for now to avoid UNIQUE errors.
$db->insert('', '{db_prefix}topics', array('id_board' => 'int', 'id_member_started' => 'int', 'id_member_updated' => 'int', 'id_first_msg' => 'int', 'id_last_msg' => 'int', 'num_replies' => 'int', 'unapproved_posts' => 'int', 'approved' => 'int', 'is_sticky' => 'int'), array((int) $id_board, $split2_firstMem, $split2_lastMem, 0, 0, $split2_replies, $split2_unapprovedposts, (int) $split2_approved, 0), array('id_topic'));
$split2_ID_TOPIC = $db->insert_id('{db_prefix}topics', 'id_topic');
if ($split2_ID_TOPIC <= 0) {
fatal_lang_error('cant_insert_topic');
}
// Move the messages over to the other topic.
$new_subject = strtr(Util::htmltrim(Util::htmlspecialchars($new_subject)), array("\r" => '', "\n" => '', "\t" => ''));
// Check the subject length.
if (Util::strlen($new_subject) > 100) {
$new_subject = Util::substr($new_subject, 0, 100);
}
// Valid subject?
if ($new_subject != '') {
$db->query('', '
UPDATE {db_prefix}messages
SET
id_topic = {int:id_topic},
subject = CASE WHEN id_msg = {int:split_first_msg} THEN {string:new_subject} ELSE {string:new_subject_replies} END
WHERE id_msg IN ({array_int:split_msgs})', array('split_msgs' => $splitMessages, 'id_topic' => $split2_ID_TOPIC, 'new_subject' => $new_subject, 'split_first_msg' => $split2_first_msg, 'new_subject_replies' => $txt['response_prefix'] . $new_subject));
// Cache the new topics subject... we can do it now as all the subjects are the same!
updateStats('subject', $split2_ID_TOPIC, $new_subject);
}
// Any associated reported posts better follow...
require_once SUBSDIR . '/Topic.subs.php';
updateSplitTopics(array('splitMessages' => $splitMessages, 'split2_ID_TOPIC' => $split2_ID_TOPIC, 'split1_replies' => $split1_replies, 'split1_first_msg' => $split1_first_msg, 'split1_last_msg' => $split1_last_msg, 'split1_firstMem' => $split1_firstMem, 'split1_lastMem' => $split1_lastMem, 'split1_unapprovedposts' => $split1_unapprovedposts, 'split1_ID_TOPIC' => $split1_ID_TOPIC, 'split2_first_msg' => $split2_first_msg, 'split2_last_msg' => $split2_last_msg, 'split2_ID_TOPIC' => $split2_ID_TOPIC, 'split2_approved' => $split2_approved), $id_board);
require_once SUBSDIR . '/FollowUps.subs.php';
// Let's see if we can create a stronger bridge between the two topics
// @todo not sure what message from the oldest topic I should link to the new one, so I'll go with the first
linkMessages($split1_first_msg, $split2_ID_TOPIC);
// Copy log topic entries.
// @todo This should really be chunked.
$request = $db->query('', '
SELECT id_member, id_msg, unwatched
FROM {db_prefix}log_topics
WHERE id_topic = {int:id_topic}', array('id_topic' => (int) $split1_ID_TOPIC));
if ($db->num_rows($request) > 0) {
$replaceEntries = array();
while ($row = $db->fetch_assoc($request)) {
$replaceEntries[] = array($row['id_member'], $split2_ID_TOPIC, $row['id_msg'], $row['unwatched']);
}
require_once SUBSDIR . '/Topic.subs.php';
markTopicsRead($replaceEntries, false);
unset($replaceEntries);
}
$db->free_result($request);
// Housekeeping.
updateTopicStats();
updateLastMessages($id_board);
logAction('split', array('topic' => $split1_ID_TOPIC, 'new_topic' => $split2_ID_TOPIC, 'board' => $id_board));
// Notify people that this topic has been split?
require_once SUBSDIR . '/Notification.subs.php';
sendNotifications($split1_ID_TOPIC, 'split');
// If there's a search index that needs updating, update it...
require_once SUBSDIR . '/Search.subs.php';
$searchAPI = findSearchAPI();
if (is_callable(array($searchAPI, 'topicSplit'))) {
$searchAPI->topicSplit($split2_ID_TOPIC, $splitMessages);
}
// Return the ID of the newly created topic.
return $split2_ID_TOPIC;
}
示例5: DumpDatabase2
//.........这里部分代码省略.........
$memory_limit = memoryReturnBytes(ini_get('memory_limit')) / 4;
$current_used_memory = 0;
$db_backup = '';
$output_function = 'un_compressed';
@ob_end_clean();
// Start saving the output... (don't do it otherwise for memory reasons.)
if (isset($_REQUEST['compress']) && function_exists('gzencode')) {
$output_function = 'gzencode';
// Send faked headers so it will just save the compressed output as a gzip.
header('Content-Type: application/x-gzip');
header('Accept-Ranges: bytes');
header('Content-Encoding: none');
// Gecko browsers... don't like this. (Mozilla, Firefox, etc.)
if (!isBrowser('gecko')) {
header('Content-Transfer-Encoding: binary');
}
// The file extension will include .gz...
$extension = '.sql.gz';
} else {
// Get rid of the gzipping alreading being done.
if (!empty($modSettings['enableCompressedOutput'])) {
@ob_end_clean();
} elseif (ob_get_length() != 0) {
ob_clean();
}
// Tell the client to save this file, even though it's text.
header('Content-Type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream'));
header('Content-Encoding: none');
// This time the extension should just be .sql.
$extension = '.sql';
}
// This should turn off the session URL parser.
$scripturl = '';
// Send the proper headers to let them download this file.
header('Content-Disposition: attachment; filename="' . $db_name . '-' . (empty($_REQUEST['struct']) ? 'data' : (empty($_REQUEST['data']) ? 'structure' : 'complete')) . '_' . strftime('%Y-%m-%d') . $extension . '"');
header('Cache-Control: private');
header('Connection: close');
// This makes things simpler when using it so very very often.
$crlf = "\r\n";
// SQL Dump Header.
$db_chunks = '-- ==========================================================' . $crlf . '--' . $crlf . '-- Database dump of tables in `' . $db_name . '`' . $crlf . '-- ' . standardTime(time(), false) . $crlf . '--' . $crlf . '-- ==========================================================' . $crlf . $crlf;
// Get all tables in the database....for our installation
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
$tables = $database->db_list_tables(false, $real_prefix . '%');
// Dump each table.
foreach ($tables as $tableName) {
// Are we dumping the structures?
if (isset($_REQUEST['struct'])) {
$db_chunks .= $crlf . '--' . $crlf . '-- Table structure for table `' . $tableName . '`' . $crlf . '--' . $crlf . $crlf . $database->db_table_sql($tableName) . ';' . $crlf;
} else {
// This is needed to speedup things later
$database->db_table_sql($tableName);
}
// How about the data?
if (!isset($_REQUEST['data']) || substr($tableName, -10) == 'log_errors') {
continue;
}
$first_round = true;
$close_table = false;
// Are there any rows in this table?
while ($get_rows = $database->insert_sql($tableName, $first_round)) {
if (empty($get_rows)) {
break;
}
// Time is what we need here!
if (function_exists('apache_reset_timeout')) {
@apache_reset_timeout();
} elseif (!empty($time_limit) && $start_time + $time_limit - 20 > time()) {
$start_time = time();
@set_time_limit(150);
}
// for the first pass, start the output with a custom line...
if ($first_round) {
$db_chunks .= $crlf . '--' . $crlf . '-- Dumping data in `' . $tableName . '`' . $crlf . '--' . $crlf . $crlf;
$first_round = false;
}
$db_chunks .= $get_rows;
$current_used_memory += Util::strlen($db_chunks);
$db_backup .= $db_chunks;
unset($db_chunks);
$db_chunks = '';
if ($current_used_memory > $memory_limit) {
echo $output_function($db_backup);
$current_used_memory = 0;
// This is probably redundant
unset($db_backup);
$db_backup = '';
}
$close_table = true;
}
// No rows to get - skip it.
if ($close_table) {
$db_backup .= '-- --------------------------------------------------------' . $crlf;
}
}
// write the last line
$db_backup .= $crlf . '-- Done' . $crlf;
echo $output_function($db_backup);
exit;
}
示例6: prepareIndexes
/**
* Fulltext_Search::prepareIndexes()
*
* Do we have to do some work with the words we are searching for to prepare them?
*
* @param string $word
* @param mixed[] $wordsSearch
* @param string[] $wordsExclude
* @param boolean $isExcluded
*/
public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
{
global $modSettings;
$subwords = text2words($word, null, false);
if (empty($modSettings['search_force_index'])) {
// A boolean capable search engine and not forced to only use an index, we may use a non indexed search
// this is harder on the server so we are restrictive here
if (count($subwords) > 1 && preg_match('~[.:@$]~', $word)) {
// Using special characters that a full index would ignore and the remaining words are
// short which would also be ignored
if (Util::strlen(current($subwords)) < $this->min_word_length && Util::strlen(next($subwords)) < $this->min_word_length) {
$wordsSearch['words'][] = trim($word, '/*- ');
$wordsSearch['complex_words'][] = count($subwords) === 1 ? $word : '"' . $word . '"';
}
} elseif (Util::strlen(trim($word, '/*- ')) < $this->min_word_length) {
// Short words have feelings too
$wordsSearch['words'][] = trim($word, '/*- ');
$wordsSearch['complex_words'][] = count($subwords) === 1 ? $word : '"' . $word . '"';
}
}
$fulltextWord = count($subwords) === 1 ? $word : '"' . $word . '"';
$wordsSearch['indexed_words'][] = $fulltextWord;
if ($isExcluded) {
$wordsExclude[] = $fulltextWord;
}
}
示例7: profileValidateSignature
//.........这里部分代码省略.........
$txt['profile_error_signature_max_font_size'] = sprintf($txt['profile_error_signature_max_font_size'], $limit_broke);
return 'signature_max_font_size';
}
}
}
// The difficult one - image sizes! Don't error on this - just fix it.
if (!empty($sig_limits[5]) || !empty($sig_limits[6])) {
// Get all BBC tags...
preg_match_all('~\\[img(\\s+width=([\\d]+))?(\\s+height=([\\d]+))?(\\s+width=([\\d]+))?\\s*\\](?:<br />)*([^<">]+?)(?:<br />)*\\[/img\\]~i', $unparsed_signature, $matches);
// ... and all HTML ones.
preg_match_all('~<img\\s+src=(?:")?((?:http://|ftp://|https://|ftps://).+?)(?:")?(?:\\s+alt=(?:")?(.*?)(?:")?)?(?:\\s?/)?>~i', $unparsed_signature, $matches2, PREG_PATTERN_ORDER);
// And stick the HTML in the BBC.
if (!empty($matches2)) {
foreach ($matches2[0] as $ind => $dummy) {
$matches[0][] = $matches2[0][$ind];
$matches[1][] = '';
$matches[2][] = '';
$matches[3][] = '';
$matches[4][] = '';
$matches[5][] = '';
$matches[6][] = '';
$matches[7][] = $matches2[1][$ind];
}
}
$replaces = array();
// Try to find all the images!
if (!empty($matches)) {
foreach ($matches[0] as $key => $image) {
$width = -1;
$height = -1;
// Does it have predefined restraints? Width first.
if ($matches[6][$key]) {
$matches[2][$key] = $matches[6][$key];
}
if ($matches[2][$key] && $sig_limits[5] && $matches[2][$key] > $sig_limits[5]) {
$width = $sig_limits[5];
$matches[4][$key] = $matches[4][$key] * ($width / $matches[2][$key]);
} elseif ($matches[2][$key]) {
$width = $matches[2][$key];
}
// ... and height.
if ($matches[4][$key] && $sig_limits[6] && $matches[4][$key] > $sig_limits[6]) {
$height = $sig_limits[6];
if ($width != -1) {
$width = $width * ($height / $matches[4][$key]);
}
} elseif ($matches[4][$key]) {
$height = $matches[4][$key];
}
// If the dimensions are still not fixed - we need to check the actual image.
if ($width == -1 && $sig_limits[5] || $height == -1 && $sig_limits[6]) {
require_once SUBSDIR . '/Attachments.subs.php';
$sizes = url_image_size($matches[7][$key]);
if (is_array($sizes)) {
// Too wide?
if ($sizes[0] > $sig_limits[5] && $sig_limits[5]) {
$width = $sig_limits[5];
$sizes[1] = $sizes[1] * ($width / $sizes[0]);
}
// Too high?
if ($sizes[1] > $sig_limits[6] && $sig_limits[6]) {
$height = $sig_limits[6];
if ($width == -1) {
$width = $sizes[0];
}
$width = $width * ($height / $sizes[1]);
} elseif ($width != -1) {
$height = $sizes[1];
}
}
}
// Did we come up with some changes? If so remake the string.
if ($width != -1 || $height != -1) {
$replaces[$image] = '[img' . ($width != -1 ? ' width=' . round($width) : '') . ($height != -1 ? ' height=' . round($height) : '') . ']' . $matches[7][$key] . '[/img]';
}
}
if (!empty($replaces)) {
$value = str_replace(array_keys($replaces), array_values($replaces), $value);
}
}
}
// Any disabled BBC?
$disabledSigBBC = implode('|', $disabledTags);
if (!empty($disabledSigBBC)) {
if (preg_match('~\\[(' . $disabledSigBBC . '[ =\\]/])~i', $unparsed_signature, $matches) !== false && isset($matches[1])) {
$disabledTags = array_unique($disabledTags);
$txt['profile_error_signature_disabled_bbc'] = sprintf($txt['profile_error_signature_disabled_bbc'], implode(', ', $disabledTags));
return 'signature_disabled_bbc';
}
}
}
preparsecode($value);
// Too long?
if (!allowedTo('admin_forum') && !empty($sig_limits[1]) && Util::strlen(str_replace('<br />', "\n", $value)) > $sig_limits[1]) {
$_POST['signature'] = trim(htmlspecialchars(str_replace('<br />', "\n", $value), ENT_QUOTES, 'UTF-8'));
$txt['profile_error_signature_max_length'] = sprintf($txt['profile_error_signature_max_length'], $sig_limits[1]);
return 'signature_max_length';
}
return true;
}
示例8: action_jsmodify
/**
* Used to edit the body or subject of a message inline
* called from action=jsmodify from script and topic js
*/
public function action_jsmodify()
{
global $modSettings, $board, $topic;
global $user_info, $context;
$db = database();
// We have to have a topic!
if (empty($topic)) {
obExit(false);
}
checkSession('get');
require_once SUBSDIR . '/Post.subs.php';
// Assume the first message if no message ID was given.
$request = $db->query('', '
SELECT
t.locked, t.num_replies, t.id_member_started, t.id_first_msg,
m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon,
m.modified_time, m.modified_name, m.approved
FROM {db_prefix}messages AS m
INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
WHERE m.id_msg = {raw:id_msg}
AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? '
AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : '
AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'], 'is_approved' => 1, 'guest_id' => 0));
if ($db->num_rows($request) == 0) {
fatal_lang_error('no_board', false);
}
$row = $db->fetch_assoc($request);
$db->free_result($request);
// Change either body or subject requires permissions to modify messages.
if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon'])) {
if (!empty($row['locked'])) {
isAllowedTo('moderate_board');
}
if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) {
if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
fatal_lang_error('modify_post_time_passed', false);
} elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) {
isAllowedTo('modify_replies');
} else {
isAllowedTo('modify_own');
}
} elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) {
isAllowedTo('modify_replies');
} else {
isAllowedTo('modify_any');
}
// Only log this action if it wasn't your message.
$moderationAction = $row['id_member'] != $user_info['id'];
}
$post_errors = Error_Context::context('post', 1);
if (isset($_POST['subject']) && Util::htmltrim(Util::htmlspecialchars($_POST['subject'])) !== '') {
$_POST['subject'] = strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
// Maximum number of characters.
if (Util::strlen($_POST['subject']) > 100) {
$_POST['subject'] = Util::substr($_POST['subject'], 0, 100);
}
} elseif (isset($_POST['subject'])) {
$post_errors->addError('no_subject');
unset($_POST['subject']);
}
if (isset($_POST['message'])) {
if (Util::htmltrim(Util::htmlspecialchars($_POST['message'])) === '') {
$post_errors->addError('no_message');
unset($_POST['message']);
} elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_POST['message']) > $modSettings['max_messageLength']) {
$post_errors->addError(array('long_message', array($modSettings['max_messageLength'])));
unset($_POST['message']);
} else {
$_POST['message'] = Util::htmlspecialchars($_POST['message'], ENT_QUOTES);
preparsecode($_POST['message']);
if (Util::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '') {
$post_errors->addError('no_message');
unset($_POST['message']);
}
}
}
if (isset($_POST['lock'])) {
if (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $row['id_member']) {
unset($_POST['lock']);
} elseif (!allowedTo('lock_any')) {
if ($row['locked'] == 1) {
unset($_POST['lock']);
} else {
$_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
}
} elseif (!empty($row['locked']) && !empty($_POST['lock']) || $_POST['lock'] == $row['locked']) {
unset($_POST['lock']);
} else {
$_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
}
}
if (isset($_POST['sticky']) && !allowedTo('make_sticky')) {
unset($_POST['sticky']);
}
if (!$post_errors->hasErrors()) {
$msgOptions = array('id' => $row['id_msg'], 'subject' => isset($_POST['subject']) ? $_POST['subject'] : null, 'body' => isset($_POST['message']) ? $_POST['message'] : null, 'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null);
//.........这里部分代码省略.........
示例9: action_ical
/**
* This function offers up a download of an event in iCal 2.0 format.
*
* follows the conventions in RFC5546 http://tools.ietf.org/html/rfc5546
* sets events as all day events since we don't have hourly events
* will honor and set multi day events
* sets a sequence number if the event has been modified.
* Accessed by action=calendar;sa=ical
*
* @todo .... allow for week or month export files as well?
*/
public function action_ical()
{
global $forum_version, $modSettings, $webmaster_email, $mbname;
// What do you think you export?
isAllowedTo('calendar_view');
// You can't export if the calendar export feature is off.
if (empty($modSettings['cal_export'])) {
fatal_lang_error('calendar_export_off', false);
}
// Goes without saying that this is required.
if (!isset($_REQUEST['eventid'])) {
fatal_lang_error('no_access', false);
}
// This is kinda wanted.
require_once SUBSDIR . '/Calendar.subs.php';
// Load up the event in question and check it exists.
$event = getEventProperties($_REQUEST['eventid']);
if ($event === false) {
fatal_lang_error('no_access', false);
}
// Check the title isn't too long - iCal requires some formatting if so.
$title = str_split($event['title'], 30);
foreach ($title as $id => $line) {
if ($id != 0) {
$title[$id] = ' ' . $title[$id];
}
$title[$id] .= "\n";
}
// Format the dates.
$datestamp = date('Ymd\\THis\\Z', time());
$datestart = $event['year'] . ($event['month'] < 10 ? '0' . $event['month'] : $event['month']) . ($event['day'] < 10 ? '0' . $event['day'] : $event['day']);
// Do we have a event that spans several days?
if ($event['span'] > 1) {
$dateend = strtotime($event['year'] . '-' . ($event['month'] < 10 ? '0' . $event['month'] : $event['month']) . '-' . ($event['day'] < 10 ? '0' . $event['day'] : $event['day']));
$dateend += ($event['span'] - 1) * 86400;
$dateend = date('Ymd', $dateend);
}
// This is what we will be sending later
$filecontents = '';
$filecontents .= 'BEGIN:VCALENDAR' . "\n";
$filecontents .= 'METHOD:PUBLISH' . "\n";
$filecontents .= 'PRODID:-//ElkArteCommunity//ElkArte ' . (empty($forum_version) ? 2.0 : strtr($forum_version, array('ElkArte ' => ''))) . '//EN' . "\n";
$filecontents .= 'VERSION:2.0' . "\n";
$filecontents .= 'BEGIN:VEVENT' . "\n";
$filecontents .= 'ORGANIZER;CN="' . $event['realname'] . '":MAILTO:' . $webmaster_email . "\n";
$filecontents .= 'DTSTAMP:' . $datestamp . "\n";
$filecontents .= 'DTSTART;VALUE=DATE:' . $datestart . "\n";
// more than one day
if ($event['span'] > 1) {
$filecontents .= 'DTEND;VALUE=DATE:' . $dateend . "\n";
}
// event has changed? advance the sequence for this UID
if ($event['sequence'] > 0) {
$filecontents .= 'SEQUENCE:' . $event['sequence'] . "\n";
}
$filecontents .= 'SUMMARY:' . implode('', $title);
$filecontents .= 'UID:' . $event['eventid'] . '@' . str_replace(' ', '-', $mbname) . "\n";
$filecontents .= 'END:VEVENT' . "\n";
$filecontents .= 'END:VCALENDAR';
// Send some standard headers.
@ob_end_clean();
if (!empty($modSettings['enableCompressedOutput'])) {
ob_start('ob_gzhandler');
} else {
ob_start();
}
// Send the file headers
header('Pragma: ');
header('Cache-Control: no-cache');
if (!isBrowser('gecko')) {
header('Content-Transfer-Encoding: binary');
}
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT');
header('Accept-Ranges: bytes');
header('Connection: close');
header('Content-Disposition: attachment; filename="' . $event['title'] . '.ics"');
if (empty($modSettings['enableCompressedOutput'])) {
header('Content-Length: ' . Util::strlen($filecontents));
}
// This is a calendar item!
header('Content-Type: text/calendar');
// Chuck out the card.
echo $filecontents;
// Off we pop - lovely!
obExit(false);
}
示例10: savePMDraft
/**
* Saves a PM draft in the user_drafts table
*
* - The core draft feature must be enabled, as well as the pm draft option
* - Determines if this is a new or and update to an existing pm draft
*
* @package Drafts
* @param mixed[] $recipientList
*/
function savePMDraft($recipientList)
{
global $context, $user_info, $modSettings;
// Ajax calling
if (!isset($context['drafts_pm_save'])) {
$context['drafts_pm_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_pm_enabled']) && allowedTo('pm_draft');
}
// PM survey says ... can you stay or must you go
if (empty($context['drafts_pm_save']) || !isset($_POST['save_draft']) || !isset($_POST['id_pm_draft'])) {
return false;
}
// Read in what was sent
$id_pm_draft = empty($_POST['id_pm_draft']) ? 0 : (int) $_POST['id_pm_draft'];
$draft_info = loadDraft($id_pm_draft, 1);
$post_errors = Error_Context::context('pm', 1);
// 5 seconds is the same limit we have for posting
if (isset($_REQUEST['xml']) && !empty($draft_info['poster_time']) && time() < $draft_info['poster_time'] + 5) {
// Send something back to the javascript caller
if (!empty($id_pm_draft)) {
loadTemplate('Xml');
$context['sub_template'] = 'xml_draft';
$context['id_draft'] = $id_pm_draft;
$context['draft_saved_on'] = $draft_info['poster_time'];
obExit();
}
return true;
}
// Determine who this is being sent to
if (isset($_REQUEST['xml'])) {
$recipientList['to'] = isset($_POST['recipient_to']) ? explode(',', $_POST['recipient_to']) : array();
$recipientList['bcc'] = isset($_POST['recipient_bcc']) ? explode(',', $_POST['recipient_bcc']) : array();
} elseif (!empty($draft_info['to_list']) && empty($recipientList)) {
$recipientList = unserialize($draft_info['to_list']);
}
// Prepare the data
$draft = array('id_pm_draft' => $id_pm_draft, 'reply_id' => empty($_POST['replied_to']) ? 0 : (int) $_POST['replied_to'], 'body' => Util::htmlspecialchars($_POST['message'], ENT_QUOTES), 'subject' => strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')), 'id_member' => $user_info['id']);
// message and subject always need a bit more work
preparsecode($draft['body']);
if (Util::strlen($draft['subject']) > 100) {
$draft['subject'] = Util::substr($draft['subject'], 0, 100);
}
// Modifying an existing PM draft?
if (!empty($id_pm_draft) && !empty($draft_info)) {
modify_pm_draft($draft, $recipientList);
// some items to return to the form
$context['draft_saved'] = true;
$context['id_pm_draft'] = $id_pm_draft;
} else {
$id_pm_draft = create_pm_draft($draft, $recipientList);
// Everything go as expected, if not toss back an error
if (!empty($id_pm_draft)) {
$context['draft_saved'] = true;
$context['id_pm_draft'] = $id_pm_draft;
} else {
$post_errors->addError('draft_not_saved');
}
}
// if we were called from the autosave function, send something back
if (!empty($id_pm_draft) && isset($_REQUEST['xml']) && !$post_errors->hasError('session_timeout')) {
loadTemplate('Xml');
$context['sub_template'] = 'xml_draft';
$context['id_draft'] = $id_pm_draft;
$context['draft_saved_on'] = time();
obExit();
}
return;
}
示例11: action_manlabels
/**
* This function handles adding, deleting and editing labels on messages.
*/
public function action_manlabels()
{
global $txt, $context, $user_info, $scripturl;
require_once SUBSDIR . '/PersonalMessage.subs.php';
// Build the link tree elements...
$context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manlabels', 'name' => $txt['pm_manage_labels']);
// Some things for the template
$context['page_title'] = $txt['pm_manage_labels'];
$context['sub_template'] = 'labels';
// Add all existing labels to the array to save, slashing them as necessary...
$the_labels = array();
foreach ($context['labels'] as $label) {
if ($label['id'] != -1) {
$the_labels[$label['id']] = $label['name'];
}
}
// Submitting changes?
if (isset($_POST['add']) || isset($_POST['delete']) || isset($_POST['save'])) {
checkSession('post');
// This will be for updating messages.
$message_changes = array();
$new_labels = array();
$rule_changes = array();
// Will most likely need this.
loadRules();
// Adding a new label?
if (isset($_POST['add'])) {
$_POST['label'] = strtr(Util::htmlspecialchars(trim($_POST['label'])), array(',' => ','));
if (Util::strlen($_POST['label']) > 30) {
$_POST['label'] = Util::substr($_POST['label'], 0, 30);
}
if ($_POST['label'] != '') {
$the_labels[] = $_POST['label'];
}
} elseif (isset($_POST['delete'], $_POST['delete_label'])) {
$i = 0;
foreach ($the_labels as $id => $name) {
if (isset($_POST['delete_label'][$id])) {
unset($the_labels[$id]);
$message_changes[$id] = true;
} else {
$new_labels[$id] = $i++;
}
}
} elseif (isset($_POST['save']) && !empty($_POST['label_name'])) {
$i = 0;
foreach ($the_labels as $id => $name) {
if ($id == -1) {
continue;
} elseif (isset($_POST['label_name'][$id])) {
// Prepare the label name
$_POST['label_name'][$id] = trim(strtr(Util::htmlspecialchars($_POST['label_name'][$id]), array(',' => ',')));
// Has to fit in the database as well
if (Util::strlen($_POST['label_name'][$id]) > 30) {
$_POST['label_name'][$id] = Util::substr($_POST['label_name'][$id], 0, 30);
}
if ($_POST['label_name'][$id] != '') {
$the_labels[(int) $id] = $_POST['label_name'][$id];
$new_labels[$id] = $i++;
} else {
unset($the_labels[(int) $id]);
$message_changes[(int) $id] = true;
}
} else {
$new_labels[$id] = $i++;
}
}
}
// Save the label status.
updateMemberData($user_info['id'], array('message_labels' => implode(',', $the_labels)));
// Update all the messages currently with any label changes in them!
if (!empty($message_changes)) {
$searchArray = array_keys($message_changes);
if (!empty($new_labels)) {
for ($i = max($searchArray) + 1, $n = max(array_keys($new_labels)); $i <= $n; $i++) {
$searchArray[] = $i;
}
}
updateLabelsToPM($searchArray, $new_labels, $user_info['id']);
// Now do the same the rules - check through each rule.
foreach ($context['rules'] as $k => $rule) {
// Each action...
foreach ($rule['actions'] as $k2 => $action) {
if ($action['t'] != 'lab' || !in_array($action['v'], $searchArray)) {
continue;
}
$rule_changes[] = $rule['id'];
// If we're here we have a label which is either changed or gone...
if (isset($new_labels[$action['v']])) {
$context['rules'][$k]['actions'][$k2]['v'] = $new_labels[$action['v']];
} else {
unset($context['rules'][$k]['actions'][$k2]);
}
}
}
}
// If we have rules to change do so now.
//.........这里部分代码省略.........
示例12: _utf8_wordwrap
/**
* Breaks a string up so its no more than width characters long
*
* - Will break at word boundaries
* - If no natural space is found will break mid-word
*
* @param string $string
* @param int $width
* @param string $break
*/
private function _utf8_wordwrap($string, $width = 75, $break = "\n")
{
$lines = array();
while (!empty($string)) {
// Get the next #width characters before a break (space, tab etc)
if (preg_match('~^(.{1,' . $width . '})(?:\\s|$)~', $string, $matches)) {
// Add the #width to the output and set up for the next pass
$lines[] = $matches[1];
$string = Util::substr($string, Util::strlen($matches[0]));
} else {
$lines[] = Util::substr($string, 0, $width);
$string = Util::substr($string, $width);
}
}
// Join it all the shortened sections up on our break characters
return implode($break, $lines);
}
示例13: _closure_js_code_chunks
/**
* Combine files in to <200k chunks and make closure compiler requests
*
* What it does:
* - Loads as many files as it can in to a single post request while
* keeping the post size within the limits accepted by the service
* - Will do multiple requests until done, combining the results
* - Returns the compressed string or the original if an error occurs
*/
private function _closure_js_code_chunks()
{
$fetch_data = '';
$combine_files = array_values($this->_combine_files);
for ($i = 0, $filecount = count($combine_files); $i < $filecount; $i++) {
// New post request, start off empty
$post_len = 0;
$post_data = '';
$post_data_raw = '';
// Combine data in to chunks of < 200k to minimize http posts
while ($i < $filecount) {
// Get the details for this file
$file = $combine_files[$i];
// Skip over minimized ones
if ($file['minimized'] === true) {
$i++;
continue;
}
// Prepare the data for posting
$data = urlencode($file['content']);
$data_len = Util::strlen($data);
// While we can add data to the post and not acceed the post size allowed by the service
if ($data_len + $post_len < 200000) {
$post_data .= $data;
$post_data_raw .= $file['content'];
$post_len = $data_len + $post_len;
$i++;
} else {
$i--;
break;
}
}
// Send it off and get the results
$post_data = '&js_code=' . $post_data;
$data = fetch_web_data($this->_url, $this->_post_header . $post_data);
// Use the results or the raw data if an error is detected
$fetch_data .= $data === false || trim($data) == '' || preg_match('/^Error\\(\\d{1,2}\\):\\s/m', $data) ? $post_data_raw : $data;
}
return $fetch_data;
}
示例14: action_mergeExecute
//.........这里部分代码省略.........
while ($row = $db->fetch_assoc($request)) {
$context['polls'][] = array('id' => $row['id_poll'], 'topic' => array('id' => $row['id_topic'], 'subject' => $row['subject']), 'question' => $row['question'], 'selected' => $row['id_topic'] == $firstTopic);
}
$db->free_result($request);
}
if (count($boards) > 1) {
foreach ($boards_info as $row) {
$context['boards'][] = array('id' => $row['id_board'], 'name' => $row['name'], 'selected' => $row['id_board'] == $topic_data[$firstTopic]['board']);
}
}
$context['topics'] = $topic_data;
foreach ($topic_data as $id => $topic) {
$context['topics'][$id]['selected'] = $topic['id'] == $firstTopic;
}
$context['page_title'] = $txt['merge'];
$context['sub_template'] = 'merge_extra_options';
return;
}
// Determine target board.
$target_board = count($boards) > 1 ? (int) $_REQUEST['board'] : $boards[0];
if (!in_array($target_board, $boards)) {
fatal_lang_error('no_board');
}
// Determine which poll will survive and which polls won't.
$target_poll = count($polls) > 1 ? (int) $_POST['poll'] : (count($polls) == 1 ? $polls[0] : 0);
if ($target_poll > 0 && !in_array($target_poll, $polls)) {
fatal_lang_error('no_access', false);
}
$deleted_polls = empty($target_poll) ? $polls : array_diff($polls, array($target_poll));
// Determine the subject of the newly merged topic - was a custom subject specified?
if (empty($_POST['subject']) && isset($_POST['custom_subject']) && $_POST['custom_subject'] != '') {
$target_subject = strtr(Util::htmltrim(Util::htmlspecialchars($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => ''));
// Keep checking the length.
if (Util::strlen($target_subject) > 100) {
$target_subject = Util::substr($target_subject, 0, 100);
}
// Nothing left - odd but pick the first topics subject.
if ($target_subject == '') {
$target_subject = $topic_data[$firstTopic]['subject'];
}
} elseif (!empty($topic_data[(int) $_POST['subject']]['subject'])) {
$target_subject = $topic_data[(int) $_POST['subject']]['subject'];
} else {
$target_subject = $topic_data[$firstTopic]['subject'];
}
// Get the first and last message and the number of messages....
$request = $db->query('', '
SELECT approved, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg, COUNT(*) AS message_count
FROM {db_prefix}messages
WHERE id_topic IN ({array_int:topics})
GROUP BY approved
ORDER BY approved DESC', array('topics' => $topics));
$topic_approved = 1;
$first_msg = 0;
while ($row = $db->fetch_assoc($request)) {
// If this is approved, or is fully unapproved.
if ($row['approved'] || !isset($first_msg)) {
$first_msg = $row['first_msg'];
$last_msg = $row['last_msg'];
if ($row['approved']) {
$num_replies = $row['message_count'] - 1;
$num_unapproved = 0;
} else {
$topic_approved = 0;
$num_replies = 0;
$num_unapproved = $row['message_count'];
示例15: shorten_html
/**
* Truncate a string up to a number of characters while preserving whole words and HTML tags
*
* This function is an adaption of the cake php function truncate in utility string.php (MIT)
*
* @param string $string text to truncate.
* @param integer $length length of returned string
* @param string $ellipsis characters to add at the end of cut string, like ...
* @param boolean $exact If to account for the $ellipsis length in returned string length
*
* @return string Trimmed string.
*/
public static function shorten_html($string, $length = 384, $ellipsis = '...', $exact = true)
{
// If its shorter than the maximum length, while accounting for html tags, simply return
if (Util::strlen(preg_replace('~<.*?>~', '', $string)) <= $length) {
return $string;
}
// Start off empty
$total_length = $exact ? Util::strlen($ellipsis) : 0;
$open_tags = array();
$truncate = '';
// Group all html open and closing tags, [1] full tag with <> [2] basic tag name [3] tag content
preg_match_all('~(<\\/?([\\w+]+)[^>]*>)?([^<>]*)~', $string, $tags, PREG_SET_ORDER);
// Walk down the stack of tags
foreach ($tags as $tag) {
// If this tag has content
if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
// Opening tag add the closing tag to the top of the stack
if (preg_match('~<[\\w]+[^>]*>~s', $tag[0])) {
array_unshift($open_tags, $tag[2]);
} elseif (preg_match('~<\\/([\\w]+)[^>]*>~s', $tag[0], $close_tag)) {
// Remove its starting tag
$pos = array_search($close_tag[1], $open_tags);
if ($pos !== false) {
array_splice($open_tags, $pos, 1);
}
}
}
// Add this (opening or closing) tag to $truncate
$truncate .= $tag[1];
// Calculate the length of the actual tag content, accounts for html entities as a single characters
$content_length = Util::strlen($tag[3]);
// Have we exceeded the allowed length limit, only add in what we are allowed
if ($content_length + $total_length > $length) {
// The number of characters which we can still return
$remaining = $length - $total_length;
$truncate .= Util::substr($tag[3], 0, $remaining);
break;
} else {
$truncate .= $tag[3];
$total_length += $content_length;
}
// Are we there yet?
if ($total_length >= $length) {
break;
}
}
// Our truncated string up to the last space
$space_pos = Util::strpos($truncate, ' ', 0, true);
$space_pos = empty($space_pos) ? $length : $space_pos;
$truncate_check = Util::substr($truncate, 0, $space_pos);
// Make sure this would not cause a cut in the middle of a tag
$lastOpenTag = (int) Util::strpos($truncate_check, '<', 0, true);
$lastCloseTag = (int) Util::strpos($truncate_check, '>', 0, true);
if ($lastOpenTag > $lastCloseTag) {
// Find the last full open tag in our truncated string, its what was being cut
preg_match_all('~<[\\w]+[^>]*>~s', $truncate, $lastTagMatches);
$last_tag = array_pop($lastTagMatches[0]);
// Set the space to just after the last tag
$space_pos = Util::strpos($truncate, $last_tag, 0, true) + strlen($last_tag);
$space_pos = empty($space_pos) ? $length : $space_pos;
}
// Look at what we are going to cut off the end of our truncated string
$bits = Util::substr($truncate, $space_pos);
// Does it cut a tag off, if so we need to know so it can be added back at the cut point
preg_match_all('~<\\/([a-z]+)>~', $bits, $dropped_tags, PREG_SET_ORDER);
if (!empty($dropped_tags)) {
if (!empty($open_tags)) {
foreach ($dropped_tags as $closing_tag) {
if (!in_array($closing_tag[1], $open_tags)) {
array_unshift($open_tags, $closing_tag[1]);
}
}
} else {
foreach ($dropped_tags as $closing_tag) {
$open_tags[] = $closing_tag[1];
}
}
}
// Cut it
$truncate = Util::substr($truncate, 0, $space_pos);
// Dot dot dot
$truncate .= $ellipsis;
// Finally close any html tags that were left open
foreach ($open_tags as $tag) {
$truncate .= '</' . $tag . '>';
}
return $truncate;
}