/** * Constructor * * @access public * @return void */ function Parse_url($str = '') { $EE =& get_instance(); if ($str == '') { $str = $EE->TMPL->tagdata; } // --------------------------------------- // Plugin Parameters // --------------------------------------- $autod = $EE->TMPL->fetch_param('find_uris', 'yes'); $parts = $EE->TMPL->fetch_param('parts', 'scheme|host|path'); $omit = $EE->TMPL->fetch_param('omit', ''); $parts = trim($parts); $omit = explode('|', $omit); if (substr($parts, 0, 3) == 'not') { $not = explode('|', trim(substr($parts, 3))); $possible = array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'); $parts = implode('|', array_diff($possible, $not)); } // --------------------------------------- // No auto-discovery? Just one big URL // --------------------------------------- if ($autod == 'no') { $str = trim($str); $str = $this->_parse_uri($str, $parts, $omit); $this->return_data = $str; return; } // --------------------------------------- // Protect Any URLs in HTML // --------------------------------------- $easy = array(); if (preg_match_all("/<.*?>/i", $str, $matches)) { $EE->load->helper('string'); $hash = unique_marker('pi_parse_url'); for ($i = 0, $s = count($matches['0']); $i < $s; $i++) { $easy[$hash . '_' . $i] = $matches['0'][$i]; $str = str_replace($matches['0'][$i], $hash . '_' . $i, $str); } } // --------------------------------------- // Find Any URLs Not in HTML // --------------------------------------- if (preg_match_all("#(http(s?)://|www\\.*)([a-z0-9@%_.~\\#\\/\\-\\?&=]+)[^\\s\\)\\<]+#i", $str, $matches)) { for ($i = 0, $s = count($matches['0']); $i < $s; $i++) { $uri = $this->_parse_uri($matches[0][$i], $parts, $omit); $str = str_replace($matches[0][$i], $uri, $str); } } // --------------------------------------- // Replace Protected HTML // --------------------------------------- if (count($easy) > 0) { foreach ($easy as $key => $value) { $str = str_replace($key, $value, $str); } } $this->return_data = $str; }
/** * Display an RTE field * * @param string $data the RTE html content * @param string $field_name the field name for the RTE field * @param array $settings field settings: * field_ta_rows - the number of textarea rows * field_text_direction - ltr or rtl * field_fmt - xhtml, br or none * * @return string */ public function display_field($data, $field_name, $settings, $container = NULL) { if (!ee()->session->cache('rte', 'loaded')) { ee()->javascript->output(ee()->rte_lib->build_js(0, '.WysiHat-field', NULL, REQ == 'CP')); ee()->session->set_cache('rte', 'loaded', TRUE); } ee()->load->helper('form'); $field = array('name' => $field_name, 'id' => $field_name, 'rows' => $settings['field_ta_rows'], 'dir' => $settings['field_text_direction']); // form prepped nonsense $code_marker = unique_marker('code'); $code_chunks = array(); $data = trim($data); $data = htmlspecialchars_decode($data, ENT_QUOTES); // Collapse tags and undo any existing newline formatting. Typography // will change it anyways and the rte will add its own. Having this here // prevents growing-newline syndrome in the rte and lets us switch // between rte and non-rte. $data = preg_replace('/<br( *\\/)?>\\n*/is', "<br>\n", $data); $data = preg_replace("/<\\/p>\n*<p>/is", "\n\n", $data); $data = preg_replace("/<br>\n/is", "\n", $data); // most newlines we should ever have is 2 $data = preg_replace('/\\n\\n+/', "\n\n", $data); // remove code chunks if (preg_match_all("/\\[code\\](.+?)\\[\\/code\\]/si", $data, $matches)) { foreach ($matches[1] as $i => $chunk) { $code_chunks[$i] = trim($chunk); $data = str_replace($matches[0][$i], $code_marker . $i, $data); } } // Check the RTE module and user's preferences if (ee()->session->userdata('rte_enabled') == 'y' and ee()->config->item('rte_enabled') == 'y') { $field['class'] = 'WysiHat-field'; foreach ($code_chunks as $i => $chunk) { $chunk = htmlentities($chunk, ENT_QUOTES, 'UTF-8'); $chunk = str_replace("\n", '<br>', $chunk); $code_chunks[$i] = $chunk; } // xhtml vs br ee()->load->library('typography'); $data = ee()->typography->auto_typography($data, TRUE); // remove non breaking spaces. typography likes to throw those // in when a list is indented. $data = str_replace(' ', ' ', $data); } // put code chunks back foreach ($code_chunks as $i => $chunk) { $data = str_replace($code_marker . $i, '[code]' . $chunk . '[/code]', $data); } // Swap {filedir_x} with the real URL. It will be converted back // upon submit by the RTE Image tool. ee()->load->model('file_upload_preferences_model'); $dirs = ee()->file_upload_preferences_model->get_file_upload_preferences(ee()->session->userdata('group_id')); foreach ($dirs as $d) { // tag to replace $filedir = "{filedir_{$d['id']}}"; $data = str_replace($filedir, $d['url'], $data); } $field['value'] = $data; $return_data = form_textarea($field); if ($container = 'grid') { $return_data = '<div class="grid_full_cell_container">' . $return_data . '</div>'; } return $return_data; }
/** * Initialize * * Reset all class properties - call after loading and before use * since CI will return the existing class when it's requested each time * inheriting the previous use's properties * * @return void */ public function initialize($config = array()) { // reset class properties $this->single_line_pgfs = TRUE; // Whether to treat single lines as paragraphs in auto-xhtml $this->text_format = 'xhtml'; // xhtml, markdown, br, none, or lite $this->html_format = 'safe'; // safe, all, none $this->auto_links = 'y'; $this->allow_img_url = 'n'; $this->parse_images = TRUE; $this->allow_headings = TRUE; $this->encode_email = TRUE; $this->encode_type = 'javascript'; // javascript or noscript $this->use_span_tags = TRUE; $this->popup_links = FALSE; $this->bounce = ''; $this->smiley_array = FALSE; $this->parse_smileys = TRUE; $this->highlight_code = TRUE; $this->convert_curly = TRUE; // Convert Curly Brackets Into Entities $this->emoticon_url = ''; $this->site_index = ''; $this->word_censor = FALSE; $this->censored_words = array(); $this->censored_replace = ''; $this->text_fmt_types = array('xhtml', 'markdown', 'br', 'none', 'lite'); $this->text_fmt_plugins = array(); $this->html_fmt_types = array('safe', 'all', 'none'); $this->yes_no_syntax = array('y', 'n'); $this->code_chunks = array(); $this->code_counter = 0; $this->http_hidden = unique_marker('typography_url_protect'); // hash to protect URLs in [url] BBCode $this->safe_img_src_end = unique_marker('typography_img_src_end'); // hash to mark end of image URLs during sanitizing of image tags foreach ($config as $key => $val) { $this->{$key} = $val; } /** ------------------------------------- /** Allowed tags /** -------------------------------------*/ // Note: The decoding array is associative, allowing more precise mapping $this->safe_encode = array('b', 'i', 'em', 'del', 'ins', 'strong', 'pre', 'code', 'blockquote'); $this->safe_decode = array('b' => 'b', 'i' => 'i', 'em' => 'em', 'del' => 'del', 'ins' => 'ins', 'strong' => 'strong', 'pre' => 'pre', 'code' => 'code', 'blockquote' => 'blockquote', 'quote' => 'blockquote', 'QUOTE' => 'blockquote'); // enable quote protection within braces for EE {variable="attributes"} $this->protect_braced_quotes = TRUE; if ($this->allow_headings == TRUE) { foreach (array('h2', 'h3', 'h4', 'h5', 'h6') as $val) { $this->safe_encode[] = $val; $this->safe_decode[$val] = $val; } } /** ------------------------------------- /** Fetch emoticon prefs /** -------------------------------------*/ if (ee()->config->item('enable_emoticons') == 'y') { $this->_fetch_emotions_prefs(); } /* ------------------------------------------- /* Hidden Configuration Variables /* - popup_link => Have links created by Typography class open in a new window (y/n) /* -------------------------------------------*/ if (ee()->config->item('popup_link') !== FALSE) { $this->popup_links = ee()->config->item('popup_link') == 'y' ? TRUE : FALSE; } /** ------------------------------------- /** Fetch word censoring prefs /** -------------------------------------*/ if (ee()->config->item('enable_censoring') == 'y') { $this->_fetch_word_censor_prefs(); } /** ------------------------------------- /** Fetch plugins /** -------------------------------------*/ ee()->load->model('addons_model'); $this->text_fmt_plugins = ee()->addons_model->get_plugin_formatting(); }
/** * Run the main parsing loop. * * Takes the data row, the preparsed tagdata, and any additonal * options and delegates to the proper parsing components. * * @param array The data row. * @param array Config items * * disable: array of components to turn off * callbacks: array of callbacks to register * * @return string Parsed tagdata */ public function parse($data, $config = array()) { $this->_data = $data; $pre = $this->_preparser; // data options $entries = $this->data('entries', array()); $absolute_offset = $this->data('absolute_offset', 0); $absolute_results = $this->data('absolute_results'); // config options $disabled = isset($config['disable']) ? $config['disable'] : array(); $callbacks = isset($config['callbacks']) ? $config['callbacks'] : array(); $pairs = $pre->pairs; $singles = $pre->singles; $prefix = $this->_prefix; $channel = $this->_channel; $subscriber_totals = $pre->subscriber_totals; $total_results = count($entries); $site_pages = config_item('site_pages'); foreach (ee()->TMPL->site_ids as $site_id) { if ($site_id != ee()->config->item('site_id')) { $pages = ee()->config->site_pages($site_id); $site_pages[$site_id] = $pages[$site_id]; } } $result = ''; // final template // If custom fields are enabled, notify them of the data we're about to send if (!empty($channel->cfields)) { $this->_send_custom_field_data_to_fieldtypes($entries); } $count = 0; $orig_tagdata = $this->_parser->tagdata(); $parser_components = $this->_parser->components(); $dt = 0; ee()->load->library('typography'); ee()->typography->initialize(array('convert_curly' => FALSE)); ee()->load->helper('date'); foreach ($entries as $row) { $tagdata = $orig_tagdata; $this->_count = $count; $row['count'] = $count + 1; $row['page_uri'] = ''; $row['page_url'] = ''; $row['total_results'] = $total_results; $row['absolute_count'] = $absolute_offset + $row['count']; $row['absolute_results'] = $absolute_results === NULL ? $total_results : $absolute_results; $row['comment_subscriber_total'] = isset($subscriber_totals[$row['entry_id']]) ? $subscriber_totals[$row['entry_id']] : 0; if ($site_pages !== FALSE && isset($site_pages[$row['site_id']]['uris'][$row['entry_id']])) { $row['page_uri'] = $site_pages[$row['site_id']]['uris'][$row['entry_id']]; $row['page_url'] = ee()->functions->create_page_url($site_pages[$row['site_id']]['url'], $site_pages[$row['site_id']]['uris'][$row['entry_id']]); } // ------------------------------------------------------- // Loop start callback. Do what you want. // Currently in use in the channel module for the // channel_entries_tagdata hook. // ------------------------------------------------------- if (isset($callbacks['tagdata_loop_start'])) { $tagdata = call_user_func($callbacks['tagdata_loop_start'], $tagdata, $row); } // ------------------------------------------------------- // Row data callback. Do what you want. // Currently in use in the channel module for the // channel_entries_row hook. // ------------------------------------------------------- if (isset($callbacks['entry_row_data'])) { $row = call_user_func($callbacks['entry_row_data'], $tagdata, $row); } // Reset custom date fields // Since custom date fields columns are integer types by default, if they // don't contain any data they return a zero. // This creates a problem if conditionals are used with those fields. // For example, if an admin has this in a template: {if mydate == ''} // Since the field contains a zero it would never evaluate TRUE. // Therefore we'll reset any zero dates to nothing. if (isset($channel->dfields[$row['site_id']]) && count($channel->dfields[$row['site_id']]) > 0) { foreach ($channel->dfields[$row['site_id']] as $dkey => $dval) { // While we're at it, kill any formatting $row['field_ft_' . $dval] = 'none'; if (isset($row['field_id_' . $dval]) and $row['field_id_' . $dval] == 0) { $row['field_id_' . $dval] = ''; } } } $this->_row = $row; // conditionals! $cond = $this->_get_conditional_data($row, $prefix, $channel); // Parse Variable Pairs foreach ($pairs as $key => $val) { $this->_tag = $key; $this->_tag_options = $val; foreach ($parser_components->pair() as $k => $component) { if (!$pre->is_disabled($component)) { $tagdata = $component->replace($tagdata, $this, $pre->pair_data($component)); } } } // Run parsers that just process tagdata once (relationships, for example) foreach ($parser_components->once() as $k => $component) { if (!$pre->is_disabled($component)) { $tagdata = $component->replace($tagdata, $this, $pre->once_data($component)); } } // We swap out the conditionals after pairs are parsed so they don't interfere // with the string replace $tagdata = ee()->functions->prep_conditionals($tagdata, $cond); // Parse individual variable tags foreach ($singles as $key => $val) { $this->_tag = $key; $this->_tag_options = $val; foreach ($parser_components->single() as $k => $component) { if (!$pre->is_disabled($component)) { $tagdata = $component->replace($tagdata, $this, $pre->single_data($component)); } } } // do we need to replace any curly braces that we protected in custom fields? if (strpos($tagdata, unique_marker('channel_bracket_open')) !== FALSE) { $tagdata = str_replace(array(unique_marker('channel_bracket_open'), unique_marker('channel_bracket_close')), array('{', '}'), $tagdata); } // ------------------------------------------------------- // Loop end callback. Do what you want. // Used by relationships to parse children and by the // channel module for the channel_entries_tagdata_end hook // ------------------------------------------------------- if (isset($callbacks['tagdata_loop_end'])) { $tagdata = call_user_func($callbacks['tagdata_loop_end'], $tagdata, $row); } $result .= $tagdata; $count++; } return $result; }
/** * Prep conditionals * * @access public * @param string * @param string * @param string * @param string * @return array */ function prep_conditionals($str, $vars, $safety = 'n', $prefix = '') { if (isset(ee()->TMPL->embed_vars)) { // If this is being called from a module tag, embedded variables // aren't going to be available yet. So this is a quick workaround // to ensure advanced conditionals using embedded variables can do // their thing in mod tags. $vars = array_merge($vars, ee()->TMPL->embed_vars); } if (count($vars) == 0) { return $str; } $switch = array(); $protect = array(); $prep_id = $this->random('alpha', 3); $embedded_tags = stristr($str, LD . 'exp:') ? TRUE : FALSE; $valid = array('!=', '==', '<=', '>=', '<', '>', '<>', '%', 'AND', 'XOR', 'OR', '&&', '||', ')', '(', 'TRUE', 'FALSE'); $str = str_replace(LD . 'if:else' . RD, unique_marker('if_else_safety'), $str); // The ((else)*if) is actually faster than (elseif|if) in PHP 5.0.4, // but only by a half a thousandth of a second. However, why not be // as efficient as possible? It also gives me a chance to catch some // user error mistakes. if (preg_match_all("/" . preg_quote(LD) . "((if:else)*if)\\s+(.*?)" . preg_quote(RD) . "/s", $str, $matches)) { // PROTECT QUOTED TEXT // That which is in quotes should be protected and ignored as it will screw // up the parsing if the variable is found within a string if (preg_match_all('/([\\"\'])([^\\1]*?)\\1/s', implode(' ', $matches[3]), $quote_matches)) { foreach ($quote_matches[0] as $ii => $quote_match) { $md5_key = (string) hexdec($prep_id . md5($quote_match)); $protect[$quote_match] = $md5_key; // To better protect quotes inside conditional quotes, we need to // determine which kind of quote to surround the newly-encoded string $surrounding_quote = surrounding_character($quote_match); if ($surrounding_quote != '"' and $surrounding_quote != "'" or $surrounding_quote === FALSE) { $surrounding_quote = '"'; } // We do these conversions on variables below, so we need // to also do them on the hardcoded values to make sure // the conditionals resolve as expected. // e.g. {if location == "pony's house"} $quote_match = $surrounding_quote . str_replace(array("'", '"', '(', ')', '$', '{', '}', "\n", "\r", '\\'), array(''', '"', '(', ')', '$', '', '', '', '', '\'), $quote_matches[2][$ii]) . $surrounding_quote; $switch[$md5_key] = $quote_match; } $matches[3] = str_replace(array_keys($protect), array_values($protect), $matches[3]); // Remove quoted values altogether to find variables... $matches['t'] = str_replace($valid, ' ', str_replace(array_values($protect), '', $matches[3])); } else { $matches['t'] = str_replace($valid, ' ', $matches[3]); } // Find what we need, nothing more!! $data = array(); foreach ($matches['t'] as $cond) { if (trim($cond) == '') { continue; } $x = preg_split("/\\s+/", trim($cond)); $i = 0; do { if (array_key_exists($x[$i], $vars)) { $data[$x[$i]] = trim($vars[$x[$i]]); } elseif ($embedded_tags === TRUE && !is_numeric($x[$i])) { $data[$x[$i]] = $x[$i]; } elseif (strncmp($x[$i], 'embed:', 6) == 0) { $data[$x[$i]] = ''; } if ($i > 500) { break; } ++$i; } while (isset($x[$i])); } // This should prevent, for example, the variable 'comment' from // overwriting the variable 'comments'. uksort($data, array($this, 'reverse_key_sort')); if ($safety == 'y') { // Make sure we have the same amount of opening conditional tags // as closing conditional tags. $tstr = preg_replace("/<script.*?" . ">.*?<\\/script>/is", '', $str); $opening = substr_count($tstr, LD . 'if') - substr_count($tstr, LD . 'if:elseif'); $closing = substr_count($tstr, LD . '/if' . RD); if ($opening > $closing) { $str .= str_repeat(LD . '/if' . RD, $opening - $closing); } } // Prep the data array to remove characters we do not want // And also just add the quotes around the value for good measure. foreach ($data as $key => &$value) { if (is_array($value)) { continue; } // TRUE AND FALSE values are for short hand conditionals, // like {if logged_in} and so we have no need to remove // unwanted characters and we do not quote it. if ($value != 'TRUE' && $value != 'FALSE' && ($key != $value or $embedded_tags !== TRUE)) { $value = '"' . str_replace(array("'", '"', '(', ')', '$', '{', '}', "\n", "\r", '\\'), array(''', '"', '(', ')', '$', '', '', '', '', '\'), strlen($value) > 100 ? substr(htmlspecialchars($value), 0, 100) : $value) . '"'; } $md5_key = (string) hexdec($prep_id . md5($key)); $protect[$key] = $md5_key; $switch[$md5_key] = $value; if ($prefix != '') { $md5_key = (string) hexdec($prep_id . md5($prefix . $key)); $protect[$prefix . $key] = $md5_key; $switch[$md5_key] = $value; } } // Example: // // {if entry_date < current_time}FUTURE{/if} // {if "{entry_date format='%Y%m%d'}" == "{current_time format='%Y%m%d'}"}Today{/if} // // The above used to fail because the second conditional would turn into something like: // // {if "{"1343930801" format='%Y%m%d'} // // So here, we make sure the value we're replacing doesn't ALSO happen to appear in the // middle of something that looks like a date field with a format parameter // // It also failed on conditionals with similar prefixes, which tends to happen with // relationship fields, e.g: // // {if parent:count == 1}one{/if} // {if parent:parent:count == 1}one{/if} // // In the second parent loop, this would evaluate as: // // {if "2" == 1}one{/if} // {if parent:"2" == 1}one{/if} // foreach ($matches[3] as &$match) { foreach ($protect as $key => $value) { // Make sure $key doesn't appear as "{$key " or ":$key " if (strpos($match, LD . $key . ' ') === FALSE and strpos($match, ':' . $key) === FALSE) { $match = str_replace($key, $value, $match); } } } if ($safety == 'y') { $matches['s'] = str_replace($protect, '^', $matches[3]); $matches['s'] = preg_replace('/"(.*?)"/s', '^', $matches['s']); $matches['s'] = preg_replace("/'(.*?)'/s", '^', $matches['s']); $matches['s'] = str_replace($valid, ' ', $matches['s']); $matches['s'] = preg_replace("/(^|\\s+)[0-9]+(\\s|\$)/", ' ', $matches['s']); // Remove unquoted numbers $done = array(); } for ($i = 0, $s = count($matches[0]); $i < $s; ++$i) { if ($safety == 'y' && !in_array($matches[0][$i], $done)) { $done[] = $matches[0][$i]; // Make sure someone did put in an {if:else conditional} // when they likely meant to have an {if:elseif conditional} if ($matches[2][$i] == '' && substr($matches[3][$i], 0, 5) == ':else' && $matches[1][$i] == 'if') { $matches[3][$i] = substr($matches[3][$i], 5); $matches[2][$i] == 'elseif'; trigger_error('Invalid Conditional, Assumed ElseIf : ' . str_replace(' :else', ':else', $matches[0][$i]), E_USER_WARNING); } // If there are parentheses, then we // try to make sure they match up correctly. $left = substr_count($matches[3][$i], '('); $right = substr_count($matches[3][$i], ')'); if ($left > $right) { $matches[3][$i] .= str_repeat(')', $left - $right); } elseif ($right > $left) { $matches[3][$i] = str_repeat('(', $right - $left) . $matches[3][$i]; } // Check for unparsed variables if (trim($matches['s'][$i]) != '' && trim($matches['s'][$i]) != '^') { $x = preg_split("/\\s+/", trim($matches['s'][$i])); for ($j = 0, $sj = count($x); $j < $sj; ++$j) { if ($x[$j] == '^') { continue; } if (substr($x[$j], 0, 1) != '^') { // We have an unset variable in the conditional. // Set the unparsed variable to FALSE $matches[3][$i] = str_replace($x[$j], 'FALSE', $matches[3][$i]); if ($this->conditional_debug === TRUE) { trigger_error('Unset EE Conditional Variable (' . $x[$j] . ') : ' . $matches[0][$i], E_USER_WARNING); } } else { // There is a partial variable match being done // because they are doing something like segment_11 // when there is no such variable but there is a segment_1 // echo $x[$j]."\n<br />\n"; trigger_error('Invalid EE Conditional Variable: ' . $matches[0][$i], E_USER_WARNING); // Set entire conditional to FALSE since it fails $matches[3][$i] = 'FALSE'; } } } } $matches[3][$i] = LD . $matches[1][$i] . ' ' . trim($matches[3][$i]) . RD; } $str = str_replace($matches[0], $matches[3], $str); $str = str_replace(array_keys($switch), array_values($switch), $str); } unset($data); unset($switch); unset($matches); unset($protect); $str = str_replace(unique_marker('if_else_safety'), LD . 'if:else' . RD, $str); return $str; }
/** ------------------------------------- /** Prevents EE Tags and Variables from being parsed /** -------------------------------------*/ function convert_curly_brackets($str) { /** ------------------------------------ /** Protect <script> tags /** ------------------------------------*/ $protected = array(); $front_protect = unique_marker('wiki_front_protect'); $back_protect = unique_marker('wiki_back_protect'); if (stristr($str, '<script') && preg_match_all("/<script.*?" . ">.*?<\\/script>/is", $str, $matches)) { for ($i = 0, $s = count($matches['0']); $i < $s; ++$i) { $protected[$front_protect . $i . $back_protect] = $matches['0'][$i]; } $str = str_replace(array_values($protected), array_keys($protected), $str); } /** ------------------------------------ /** Encode all other curly brackets /** ------------------------------------*/ $str = str_replace(array(LD, RD), array('{', '}'), $str); /** ------------------------------------ /** Convert back and return /** ------------------------------------*/ if (count($protected) > 0) { $str = str_replace(array_keys($protected), array_values($protected), $str); } return $str; }
/** * Display an RTE field * * @param string $data the RTE html content * @param string $field_name the field name for the RTE field * @param array $settings field settings: * field_ta_rows - the number of textarea rows * field_text_direction - ltr or rtl * field_fmt - xhtml, br or none * * @return string */ public function display_field($data, $field_name, $settings, $container = NULL) { if (!ee()->session->cache('rte', 'loaded')) { ee()->javascript->output(ee()->rte_lib->build_js(0, '.WysiHat-field', NULL, REQ == 'CP')); ee()->session->set_cache('rte', 'loaded', TRUE); } ee()->load->helper('form'); $field = array('name' => $field_name, 'id' => $field_name, 'rows' => $settings['field_ta_rows'], 'dir' => $settings['field_text_direction'], 'class' => 'has-rte'); // form prepped nonsense $code_marker = unique_marker('code'); $code_chunks = array(); $data = trim($data); $data = htmlspecialchars_decode($data, ENT_QUOTES); $data = $this->clean_data($data); // Check the RTE module and user's preferences if (ee()->session->userdata('rte_enabled') == 'y' and ee()->config->item('rte_enabled') == 'y') { $field['class'] .= ' WysiHat-field'; foreach ($code_chunks as $i => $chunk) { $chunk = htmlentities($chunk, ENT_QUOTES, 'UTF-8'); $chunk = str_replace("\n", '<br>', $chunk); $code_chunks[$i] = $chunk; } // xhtml vs br ee()->load->library('typography'); $data = ee()->typography->auto_typography($data, TRUE); // remove non breaking spaces. typography likes to throw those // in when a list is indented. $data = str_replace(' ', ' ', $data); } // put code chunks back foreach ($code_chunks as $i => $chunk) { $data = str_replace($code_marker . $i, '[code]' . $chunk . '[/code]', $data); } // Swap {filedir_x} with the real URL. It will be converted back // upon submit by the RTE Image tool. ee()->load->model('file_upload_preferences_model'); $dirs = ee()->file_upload_preferences_model->get_file_upload_preferences(ee()->session->userdata('group_id')); foreach ($dirs as $d) { // tag to replace $filedir = "{filedir_{$d['id']}}"; $data = str_replace($filedir, $d['url'], $data); } $field['value'] = $data; $return_data = form_textarea($field); return $return_data; }
/** * Replace all of the custom channel fields. * * @param String The tagdata to be parsed * @param Object The channel parser object * @param Mixed The results from the preparse method * * @return String The processed tagdata */ public function replace($tagdata, EE_Channel_data_parser $obj, $ft_api) { $tag = $obj->tag(); $data = $obj->row(); $prefix = $obj->prefix(); $site_id = $data['site_id']; $cfields = $obj->channel()->cfields; $rfields = $obj->channel()->rfields; $rfields = isset($rfields[$site_id]) ? $rfields[$site_id] : array(); $cfields = isset($cfields[$site_id]) ? $cfields[$site_id] : array(); $cfields = array_diff_key($cfields, $rfields); if (empty($cfields)) { return $tagdata; } $field = ee()->api_channel_fields->get_single_field($tag, $prefix); if (isset($cfields[$field['field_name']])) { $entry = ''; $field_id = $cfields[$field['field_name']]; if (isset($data['field_id_' . $field_id]) && $data['field_id_' . $field_id] !== '') { $modifier = $field['modifier']; $parse_fnc = $modifier ? 'replace_' . $modifier : 'replace_tag'; $obj = $ft_api->setup_handler($field_id, TRUE); if ($obj) { $_ft_path = $ft_api->ft_paths[$ft_api->field_type]; ee()->load->add_package_path($_ft_path, FALSE); $obj->_init(array('row' => $data, 'content_id' => $data['entry_id'], 'content_type' => 'channel')); $data = $ft_api->apply('pre_process', array($data['field_id_' . $field_id])); if (method_exists($obj, $parse_fnc)) { $entry = $ft_api->apply($parse_fnc, array($data, $field['params'], FALSE)); } elseif (method_exists($obj, 'replace_tag_catchall')) { $entry = $ft_api->apply('replace_tag_catchall', array($data, $field['params'], FALSE, $modifier)); } ee()->load->remove_package_path($_ft_path); } else { // Couldn't find a fieldtype $entry = ee()->typography->parse_type(ee()->functions->encode_ee_tags($data['field_id_' . $field_id]), array('text_format' => $data['field_ft_' . $field_id], 'html_format' => $data['channel_html_formatting'], 'auto_links' => $data['channel_auto_link_urls'], 'allow_img_url' => $data['channel_allow_img_urls'])); } // prevent accidental parsing of other channel variables in custom field data if (strpos($entry, '{') !== FALSE) { $entry = str_replace(array('{', '}'), array(unique_marker('channel_bracket_open'), unique_marker('channel_bracket_close')), $entry); } $tagdata = str_replace(LD . $tag . RD, $entry, $tagdata); } $tagdata = str_replace(LD . $tag . RD, '', $tagdata); } return $tagdata; }
/** * Protect compressed javascript. * * @see `$this->enableProtectJavascript()` for why we do this. * * @param String $str The raw template string * @return String The template string with javascript escaped */ private function protectJavascript($str) { if ($this->protect_javascript === FALSE) { return $str; } $js_protect = unique_marker('tmpl_script'); if (stristr($str, '<script') && preg_match_all('/<script.*?>.*?<\\/script>/is', $str, $matches)) { foreach ($matches[0] as $i => $match) { $this->protected_javascript[$js_protect . $i] = $match; } $str = str_replace(array_values($this->protected_javascript), array_keys($this->protected_javascript), $str); } return $str; }
/** * Parse channel entries */ public function parse_channel_entries() { $switch = array(); $processed_member_fields = array(); // Set default date header variables $heading_date_hourly = 0; $heading_flag_hourly = 0; $heading_flag_weekly = 1; $heading_date_daily = 0; $heading_flag_daily = 0; $heading_date_monthly = 0; $heading_flag_monthly = 0; $heading_date_yearly = 0; $heading_flag_yearly = 0; // Fetch the "category chunk" // We'll grab the category data now to avoid processing cycles in the foreach loop below $cat_chunk = array(); if (strpos($this->EE->TMPL->tagdata, LD . '/categories' . RD) !== FALSE) { if (preg_match_all("/" . LD . "categories(.*?)" . RD . "(.*?)" . LD . '\\/' . 'categories' . RD . "/s", $this->EE->TMPL->tagdata, $matches)) { for ($j = 0; $j < count($matches[0]); $j++) { $cat_chunk[] = array($matches[2][$j], $this->EE->functions->assign_parameters($matches[1][$j]), $matches[0][$j]); } } } // Fetch all the date-related variables $entry_date = array(); $gmt_date = array(); $gmt_entry_date = array(); $edit_date = array(); $gmt_edit_date = array(); $expiration_date = array(); $week_date = array(); // We do this here to avoid processing cycles in the foreach loop $date_vars = array('entry_date', 'gmt_date', 'gmt_entry_date', 'edit_date', 'gmt_edit_date', 'expiration_date', 'recent_comment_date', 'week_date'); $date_variables_exist = FALSE; foreach ($date_vars as $val) { if (strpos($this->EE->TMPL->tagdata, LD . $val) === FALSE) { continue; } if (preg_match_all("/" . LD . $val . "\\s+format=([\"'])([^\\1]*?)\\1" . RD . "/s", $this->EE->TMPL->tagdata, $matches)) { $date_variables_exist = TRUE; for ($j = 0; $j < count($matches[0]); $j++) { $matches[0][$j] = str_replace(array(LD, RD), '', $matches[0][$j]); switch ($val) { case 'entry_date': $entry_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; case 'gmt_date': $gmt_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; case 'gmt_entry_date': $gmt_entry_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; case 'edit_date': $edit_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; case 'gmt_edit_date': $gmt_edit_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; case 'expiration_date': $expiration_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; case 'recent_comment_date': $recent_comment_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; case 'week_date': $week_date[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[2][$j]); break; } } } } // Are any of the custom fields dates? $custom_date_fields = array(); if (count($this->dfields) > 0) { foreach ($this->dfields as $site_id => $dfields) { foreach ($dfields as $key => $value) { if (strpos($this->EE->TMPL->tagdata, LD . $key) === FALSE) { continue; } if (preg_match_all("/" . LD . $key . "\\s+format=[\"'](.*?)[\"']" . RD . "/s", $this->EE->TMPL->tagdata, $matches)) { for ($j = 0; $j < count($matches[0]); $j++) { $matches[0][$j] = str_replace(array(LD, RD), '', $matches[0][$j]); $custom_date_fields[$matches[0][$j]] = $this->EE->localize->fetch_date_params($matches[1][$j]); } } } } } // And the same again for reverse related entries $reverse_markers = array(); if (preg_match_all("/" . LD . "REV_REL\\[([^\\]]+)\\]REV_REL" . RD . "/", $this->EE->TMPL->tagdata, $matches)) { for ($j = 0; $j < count($matches['0']); $j++) { $reverse_markers[$matches['1'][$j]] = ''; } } // "Search by Member" link // We use this with the {member_search_path} variable $result_path = preg_match("/" . LD . "member_search_path\\s*=(.*?)" . RD . "/s", $this->EE->TMPL->tagdata, $match) ? $match[1] : 'search/results'; $result_path = str_replace(array('"', "'"), "", $result_path); $search_link = $this->EE->functions->fetch_site_index(0, 0) . QUERY_MARKER . 'ACT=' . $this->EE->functions->fetch_action_id('Search', 'do_search') . '&result_path=' . $result_path . '&mbr='; // Start the main processing loop // For our hook to work, we need to grab the result array $query_result = $this->query->result_array(); // Ditch everything else $this->query->free_result(); unset($this->query); // ------------------------------------------- // 'channel_entries_query_result' hook. // - Take the whole query result array, do what you wish // - added 1.6.7 // if ($this->EE->extensions->active_hook('channel_entries_query_result') === TRUE) { $query_result = $this->EE->extensions->call('channel_entries_query_result', $this, $query_result); if ($this->EE->extensions->end_script === TRUE) { return $this->EE->TMPL->tagdata; } } // // ------------------------------------------- $total_results = count($query_result); $site_pages = $this->EE->config->item('site_pages'); // Fetch Custom Field Chunks // If any of our custom fields are tag pair fields, we'll grab those chunks now // Moved below hook in 2.6 $pfield_chunk = array(); if (count($this->pfields) > 0) { foreach ($this->pfields as $site_id => $pfields) { $pfield_names = array_intersect($this->cfields[$site_id], array_keys($pfields)); foreach ($pfield_names as $field_name => $field_id) { $offset = 0; while (($end = strpos($this->EE->TMPL->tagdata, LD . '/' . $field_name . RD, $offset)) !== FALSE) { // This hurts soo much. Using custom fields as pair and single vars in the same // channel tags could lead to something like this: {field}...{field}inner{/field} // There's no efficient regex to match this case, so we'll find the last nested // opening tag and re-cut the chunk. if (preg_match("/" . LD . "{$field_name}(.*?)" . RD . "(.*?)" . LD . '\\/' . "{$field_name}(.*?)" . RD . "/s", $this->EE->TMPL->tagdata, $matches, 0, $offset)) { $chunk = $matches[0]; $params = $matches[1]; $inner = $matches[2]; // We might've sandwiched a single tag - no good, check again (:sigh:) if (strpos($chunk, LD . $field_name, 1) !== FALSE && preg_match_all("/" . LD . "{$field_name}(.*?)" . RD . "/s", $chunk, $match)) { // Let's start at the end $idx = count($match[0]) - 1; $tag = $match[0][$idx]; // Reassign the parameter $params = $match[1][$idx]; // Cut the chunk at the last opening tag (PHP5 could do this with strrpos :-( ) while (strpos($chunk, $tag, 1) !== FALSE) { $chunk = substr($chunk, 1); $chunk = strstr($chunk, LD . $field_name); $inner = substr($chunk, strlen($tag), -strlen(LD . '/' . $field_name . RD)); } } $chunk_array = array($inner, $this->EE->functions->assign_parameters($params), $chunk); // Grab modifier if it exists and add it to the chunk array if (substr($params, 0, 1) == ':') { $chunk_array[] = str_replace(':', '', $params); } $pfield_chunk[$site_id][$field_name][] = $chunk_array; } $offset = $end + 1; } /* if (($end = strpos($this->EE->TMPL->tagdata, LD.'/'.$field_name.RD)) !== FALSE) { // This hurts soo much. Using custom fields as pair and single vars in the same // channel tags could lead to something like this: {field}...{field}inner{/field} // There's no efficient regex to match this case, so we'll find the last nested // opening tag and re-cut the chunk. if (preg_match_all("/".LD."{$field_name}(.*?)".RD."(.*?)".LD.'\/'.$field_name.RD."/s", $this->EE->TMPL->tagdata, $matches)) { for ($j = 0; $j < count($matches[0]); $j++) { $chunk = $matches[0][$j]; $params = $matches[1][$j]; $inner = $matches[2][$j]; // We might've sandwiched a single tag - no good, check again (:sigh:) if ((strpos($chunk, LD.$field_name, 1) !== FALSE) && preg_match_all("/".LD."{$field_name}(.*?)".RD."/s", $chunk, $match)) { // Let's start at the end $idx = count($match[0]) - 1; $tag = $match[0][$idx]; // Cut the chunk at the last opening tag (PHP5 could do this with strrpos :-( ) while (strpos($chunk, $tag, 1) !== FALSE) { $chunk = substr($chunk, 1); $chunk = strstr($chunk, LD.$field_name); $inner = substr($chunk, strlen($tag), -strlen(LD.'/'.$field_name.RD)); } } $pfield_chunk[$site_id][$field_name][] = array($inner, $this->EE->functions->assign_parameters($params), $chunk); } } } */ } } } // One more preloop check - custom fields with modifiers in conditionals $all_field_names = array(); foreach ($this->cfields as $site_id => $fields) { $all_field_names = array_unique(array_merge($all_field_names, $fields)); } $modified_field_options = implode('|', array_keys($all_field_names)); $modified_conditionals = array(); if (preg_match_all("/" . preg_quote(LD) . "((if:(else))*if)\\s+(({$modified_field_options}):(\\w+))(.*?)" . preg_quote(RD) . "/s", $this->EE->TMPL->tagdata, $matches)) { foreach ($matches[5] as $match_key => $field_name) { $modified_conditionals[$field_name][] = $matches[6][$match_key]; } } $modified_conditionals = array_map('array_unique', $modified_conditionals); unset($all_field_names, $modified_field_options); // If custom fields are enabled, notify them of the data we're about to send if (!empty($this->cfields)) { $this->_send_custom_field_data_to_fieldtypes($query_result); } foreach ($query_result as $count => $row) { // Fetch the tag block containing the variables that need to be parsed $tagdata = $this->EE->TMPL->tagdata; $row['count'] = $count + 1; $row['page_uri'] = ''; $row['page_url'] = ''; $row['total_results'] = $total_results; $row['absolute_count'] = $this->pagination->offset + $row['count']; $row['absolute_results'] = $this->absolute_results === NULL ? $total_results : $this->absolute_results; if ($site_pages !== FALSE && isset($site_pages[$row['site_id']]['uris'][$row['entry_id']])) { $row['page_uri'] = $site_pages[$row['site_id']]['uris'][$row['entry_id']]; $row['page_url'] = $this->EE->functions->create_page_url($site_pages[$row['site_id']]['url'], $site_pages[$row['site_id']]['uris'][$row['entry_id']]); } // ------------------------------------------- // 'channel_entries_tagdata' hook. // - Take the entry data and tag data, do what you wish // if ($this->EE->extensions->active_hook('channel_entries_tagdata') === TRUE) { $tagdata = $this->EE->extensions->call('channel_entries_tagdata', $tagdata, $row, $this); if ($this->EE->extensions->end_script === TRUE) { return $tagdata; } } // // ------------------------------------------- // ------------------------------------------- // 'channel_entries_row' hook. // - Take the entry data, do what you wish // - added 1.6.7 // if ($this->EE->extensions->active_hook('channel_entries_row') === TRUE) { $row = $this->EE->extensions->call('channel_entries_row', $this, $row); if ($this->EE->extensions->end_script === TRUE) { return $tagdata; } } // // ------------------------------------------- // Adjust dates if needed // If the "dst_enabled" item is set in any given entry // we need to offset to the timestamp by an hour if (!isset($row['dst_enabled'])) { $row['dst_enabled'] = 'n'; } /**-- /** Reset custom date fields /**--*/ // Since custom date fields columns are integer types by default, if they // don't contain any data they return a zero. // This creates a problem if conditionals are used with those fields. // For example, if an admin has this in a template: {if mydate == ''} // Since the field contains a zero it would never evaluate TRUE. // Therefore we'll reset any zero dates to nothing. if (isset($this->dfields[$row['site_id']]) && count($this->dfields[$row['site_id']]) > 0) { foreach ($this->dfields[$row['site_id']] as $dkey => $dval) { // While we're at it, kill any formatting $row['field_ft_' . $dval] = 'none'; if (isset($row['field_id_' . $dval]) and $row['field_id_' . $dval] == 0) { $row['field_id_' . $dval] = ''; } } } // While we're at it, do the same for related entries. if (isset($this->rfields[$row['site_id']]) && count($this->rfields[$row['site_id']]) > 0) { foreach ($this->rfields[$row['site_id']] as $rkey => $rval) { $row['field_ft_' . $rval] = 'none'; } } // Reverse related markers $j = 0; foreach ($reverse_markers as $k => $v) { $this->reverse_related_entries[$row['entry_id']][$j] = $k; $tagdata = str_replace(LD . "REV_REL[" . $k . "]REV_REL" . RD, LD . "REV_REL[" . $k . "][" . $row['entry_id'] . "]REV_REL" . RD, $tagdata); $j++; } // Conditionals $cond = $row; $cond['logged_in'] = $this->EE->session->userdata('member_id') == 0 ? 'FALSE' : 'TRUE'; $cond['logged_out'] = $this->EE->session->userdata('member_id') != 0 ? 'FALSE' : 'TRUE'; if ($row['comment_expiration_date'] > 0 && $this->EE->localize->now > $row['comment_expiration_date'] && $this->EE->config->item('comment_moderation_override') !== 'y' or $row['allow_comments'] == 'n' or isset($row['comment_system_enabled']) && $row['comment_system_enabled'] == 'n') { $cond['allow_comments'] = 'FALSE'; } else { $cond['allow_comments'] = 'TRUE'; } foreach (array('avatar_filename', 'photo_filename', 'sig_img_filename') as $pv) { if (!isset($row[$pv])) { $row[$pv] = ''; } } $cond['signature_image'] = ($row['sig_img_filename'] == '' or $this->EE->config->item('enable_signatures') == 'n' or $this->EE->session->userdata('display_signatures') == 'n') ? 'FALSE' : 'TRUE'; $cond['avatar'] = ($row['avatar_filename'] == '' or $this->EE->config->item('enable_avatars') == 'n' or $this->EE->session->userdata('display_avatars') == 'n') ? 'FALSE' : 'TRUE'; $cond['photo'] = ($row['photo_filename'] == '' or $this->EE->config->item('enable_photos') == 'n' or $this->EE->session->userdata('display_photos') == 'n') ? 'FALSE' : 'TRUE'; $cond['forum_topic'] = empty($row['forum_topic_id']) ? 'FALSE' : 'TRUE'; $cond['not_forum_topic'] = !empty($row['forum_topic_id']) ? 'FALSE' : 'TRUE'; $cond['category_request'] = $this->cat_request === FALSE ? 'FALSE' : 'TRUE'; $cond['not_category_request'] = $this->cat_request !== FALSE ? 'FALSE' : 'TRUE'; $cond['channel'] = $row['channel_title']; $cond['channel_short_name'] = $row['channel_name']; $cond['author'] = $row['screen_name'] != '' ? $row['screen_name'] : $row['username']; $cond['photo_url'] = $this->EE->config->slash_item('photo_url') . $row['photo_filename']; $cond['photo_image_width'] = $row['photo_width']; $cond['photo_image_height'] = $row['photo_height']; $cond['avatar_url'] = $this->EE->config->slash_item('avatar_url') . $row['avatar_filename']; $cond['avatar_image_width'] = $row['avatar_width']; $cond['avatar_image_height'] = $row['avatar_height']; $cond['signature_image_url'] = $this->EE->config->slash_item('sig_img_url') . $row['sig_img_filename']; $cond['signature_image_width'] = $row['sig_img_width']; $cond['signature_image_height'] = $row['sig_img_height']; $cond['relative_date'] = $this->EE->localize->format_timespan($this->EE->localize->now - $row['entry_date']); if (isset($this->cfields[$row['site_id']])) { foreach ($this->cfields[$row['site_id']] as $key => $value) { $cond[$key] = !isset($row['field_id_' . $value]) ? '' : $row['field_id_' . $value]; // Is this field used with a modifier anywhere? if (isset($modified_conditionals[$key]) && count($modified_conditionals[$key])) { $this->EE->load->library('api'); $this->EE->api->instantiate('channel_fields'); if ($this->EE->api_channel_fields->setup_handler($value)) { foreach ($modified_conditionals[$key] as $modifier) { $this->EE->api_channel_fields->apply('_init', array(array('row' => $row))); $data = $this->EE->api_channel_fields->apply('pre_process', array($cond[$key])); if ($this->EE->api_channel_fields->check_method_exists('replace_' . $modifier)) { $cond[$key . ':' . $modifier] = $this->EE->api_channel_fields->apply('replace_' . $modifier, array($data, array(), FALSE)); } else { $cond[$key . ':' . $modifier] = FALSE; $this->EE->TMPL->log_item('Unable to find parse type for custom field conditional: ' . $key . ':' . $modifier); } } } } } } foreach ($this->mfields as $key => $value) { $cond[$key] = !array_key_exists('m_field_id_' . $value[0], $row) ? '' : $row['m_field_id_' . $value[0]]; //( ! isset($row['m_field_id_'.$value[0]])) ? '' : $row['m_field_id_'.$value[0]]; } //$tagdata = $this->EE->functions->prep_conditionals($tagdata, $cond); // Reset custom variable pair cache $parsed_custom_pairs = array(); // Parse Variable Pairs foreach ($this->EE->TMPL->var_pair as $key => $val) { // parse categories if (strncmp($key, 'categories', 10) == 0) { if (isset($this->categories[$row['entry_id']]) and is_array($this->categories[$row['entry_id']]) and count($cat_chunk) > 0) { // Get category ID from URL for {if active} conditional $this->EE->load->helper('segment'); $active_cat = $this->pagination->dynamic_sql && $this->cat_request ? parse_category($this->query_string) : FALSE; foreach ($cat_chunk as $catkey => $catval) { $cats = ''; $i = 0; // We do the pulling out of categories before the "prepping" of conditionals // So, we have to do it here again too. How annoying... $catval[0] = $this->EE->functions->prep_conditionals($catval[0], $cond); $catval[2] = $this->EE->functions->prep_conditionals($catval[2], $cond); $not_these = array(); $these = array(); $not_these_groups = array(); $these_groups = array(); if (isset($catval[1]['show'])) { if (strncmp($catval[1]['show'], 'not ', 4) == 0) { $not_these = explode('|', trim(substr($catval[1]['show'], 3))); } else { $these = explode('|', trim($catval[1]['show'])); } } if (isset($catval[1]['show_group'])) { if (strncmp($catval[1]['show_group'], 'not ', 4) == 0) { $not_these_groups = explode('|', trim(substr($catval[1]['show_group'], 3))); } else { $these_groups = explode('|', trim($catval[1]['show_group'])); } } foreach ($this->categories[$row['entry_id']] as $k => $v) { if (in_array($v[0], $not_these) or isset($v[5]) && in_array($v[5], $not_these_groups)) { continue; } elseif (count($these) > 0 && !in_array($v[0], $these) or count($these_groups) > 0 && isset($v[5]) && !in_array($v[5], $these_groups)) { continue; } $temp = $catval[0]; if (preg_match_all("#" . LD . "path=(.+?)" . RD . "#", $temp, $matches)) { foreach ($matches[1] as $match) { if ($this->use_category_names == TRUE) { $temp = preg_replace("#" . LD . "path=.+?" . RD . "#", $this->EE->functions->remove_double_slashes($this->EE->functions->create_url($match) . '/' . $this->reserved_cat_segment . '/' . $v[6]), $temp, 1); } else { $temp = preg_replace("#" . LD . "path=.+?" . RD . "#", $this->EE->functions->remove_double_slashes($this->EE->functions->create_url($match) . '/C' . $v[0]), $temp, 1); } } } else { $temp = preg_replace("#" . LD . "path=.+?" . RD . "#", $this->EE->functions->create_url("SITE_INDEX"), $temp); } $this->EE->load->library('file_field'); $cat_image = $this->EE->file_field->parse_field($v[3]); $cat_vars = array('category_name' => $v[2], 'category_url_title' => $v[6], 'category_description' => isset($v[4]) ? $v[4] : '', 'category_group' => isset($v[5]) ? $v[5] : '', 'category_image' => $cat_image['url'], 'category_id' => $v[0], 'parent_id' => $v[1], 'active' => $active_cat == $v[0] || $active_cat == $v[6]); // add custom fields for conditionals prep foreach ($this->catfields as $cv) { $cat_vars[$cv['field_name']] = !isset($v['field_id_' . $cv['field_id']]) ? '' : $v['field_id_' . $cv['field_id']]; } $temp = $this->EE->functions->prep_conditionals($temp, $cat_vars); $temp = str_replace(array(LD . "category_id" . RD, LD . "category_name" . RD, LD . "category_url_title" . RD, LD . "category_image" . RD, LD . "category_group" . RD, LD . 'category_description' . RD, LD . 'parent_id' . RD), array($v[0], $v[2], $v[6], $cat_image['url'], isset($v[5]) ? $v[5] : '', isset($v[4]) ? $v[4] : '', $v[1]), $temp); foreach ($this->catfields as $cv2) { if (isset($v['field_id_' . $cv2['field_id']]) and $v['field_id_' . $cv2['field_id']] != '') { $field_content = $this->EE->typography->parse_type($v['field_id_' . $cv2['field_id']], array('text_format' => $v['field_ft_' . $cv2['field_id']], 'html_format' => $v['field_html_formatting'], 'auto_links' => 'n', 'allow_img_url' => 'y')); $temp = str_replace(LD . $cv2['field_name'] . RD, $field_content, $temp); } else { // garbage collection $temp = str_replace(LD . $cv2['field_name'] . RD, '', $temp); } $temp = $this->EE->functions->remove_double_slashes($temp); } $cats .= $temp; if (is_array($catval[1]) && isset($catval[1]['limit']) && $catval[1]['limit'] == ++$i) { break; } } if (is_array($catval[1]) and isset($catval[1]['backspace'])) { $cats = substr($cats, 0, -$catval[1]['backspace']); } // Check to see if we need to parse {filedir_n} if (strpos($cats, '{filedir_') !== FALSE) { $this->EE->load->library('file_field'); $cats = $this->EE->file_field->parse_string($cats); } $tagdata = str_replace($catval[2], $cats, $tagdata); } } else { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'categories', $tagdata); } } // END CATEGORIES // parse custom field pairs (file, checkbox, multiselect) // First we need the key name out of the {name foo=bar|baz} mess $key_name = $key; $parse_fnc_catchall = 'replace_tag_catchall'; if (($spc = strpos($key, ' ')) !== FALSE) { $key_name = substr($key, 0, $spc); } if (($cln = strpos($key, ':')) !== FALSE) { $key_name = substr($key_name, 0, $cln); } // Is it a custom field? if (isset($this->cfields[$row['site_id']][$key_name]) && !in_array($key_name, $parsed_custom_pairs)) { // We parse all chunks, but TMPL->var_pairs will still have the others // so we'll keep track of these and bail if we've parsed it $parsed_custom_pairs[] = $key_name; // Is this custom field part of the current channel row? if (isset($row['field_id_' . $this->cfields[$row['site_id']][$key_name]]) && isset($this->pfields[$row['site_id']][$this->cfields[$row['site_id']][$key_name]])) { $this->EE->load->library('api'); $this->EE->api->instantiate('channel_fields'); if ($this->EE->api_channel_fields->setup_handler($this->cfields[$row['site_id']][$key_name])) { $this->EE->api_channel_fields->apply('_init', array(array('row' => $row))); // Preprocess $data = $this->EE->api_channel_fields->apply('pre_process', array($row['field_id_' . $this->cfields[$row['site_id']][$key_name]])); // Blast through all the chunks if (isset($pfield_chunk[$row['site_id']][$key_name])) { foreach ($pfield_chunk[$row['site_id']][$key_name] as $chk_data) { // Set up parse function name based on whether or not // we have a modifier $parse_fnc = isset($chk_data[3]) ? 'replace_' . $chk_data[3] : 'replace_tag'; if ($this->EE->api_channel_fields->check_method_exists($parse_fnc)) { $tpl_chunk = $this->EE->api_channel_fields->apply($parse_fnc, array($data, $chk_data[1], $chk_data[0])); } elseif ($this->EE->api_channel_fields->check_method_exists($parse_fnc_catchall) and isset($chk_data[3])) { $tpl_chunk = $this->EE->api_channel_fields->apply($parse_fnc_catchall, array($data, $chk_data[1], $chk_data[0], $chk_data[3])); } else { $tpl_chunk = ''; $this->EE->TMPL->log_item('Unable to find parse type for custom field: ' . $key_name); } // Replace the chunk $tagdata = str_replace($chk_data[2], $tpl_chunk, $tagdata); } } } else { $this->EE->TMPL->log_item('Unable to find field type for custom field: ' . $key); $tagdata = $this->EE->TMPL->delete_var_pairs($key, $key_name, $tagdata); } } else { $tagdata = $this->EE->TMPL->delete_var_pairs($key, $key_name, $tagdata); } } // END CUSTOM FIELD PAIRS // parse date heading if (strncmp($key, 'date_heading', 12) == 0) { // Set the display preference $display = (is_array($val) and isset($val['display'])) ? $val['display'] : 'daily'; // Hourly header if ($display == 'hourly') { $heading_date_hourly = gmdate('YmdH', $this->EE->localize->set_localized_time($row['entry_date'])); if ($heading_date_hourly == $heading_flag_hourly) { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_heading', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_heading', $tagdata); $heading_flag_hourly = $heading_date_hourly; } } elseif ($display == 'weekly') { $temp_date = $this->EE->localize->set_localized_time($row['entry_date']); // date()'s week variable 'W' starts weeks on Monday per ISO-8601. // By default we start weeks on Sunday, so we need to do a little dance for // entries made on Sundays to make sure they get placed in the right week heading if (strtolower($this->EE->TMPL->fetch_param('start_day')) != 'monday' && gmdate('w', $this->EE->localize->set_localized_time($row['entry_date'])) == 0) { // add 7 days to toss us into the next ISO-8601 week $heading_date_weekly = gmdate('YW', $temp_date + 604800); } else { $heading_date_weekly = gmdate('YW', $temp_date); } if ($heading_date_weekly == $heading_flag_weekly) { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_heading', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_heading', $tagdata); $heading_flag_weekly = $heading_date_weekly; } } elseif ($display == 'monthly') { $heading_date_monthly = gmdate('Ym', $this->EE->localize->set_localized_time($row['entry_date'])); if ($heading_date_monthly == $heading_flag_monthly) { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_heading', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_heading', $tagdata); $heading_flag_monthly = $heading_date_monthly; } } elseif ($display == 'yearly') { $heading_date_yearly = gmdate('Y', $this->EE->localize->set_localized_time($row['entry_date'])); if ($heading_date_yearly == $heading_flag_yearly) { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_heading', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_heading', $tagdata); $heading_flag_yearly = $heading_date_yearly; } } else { $heading_date_daily = gmdate('Ymd', $this->EE->localize->set_localized_time($row['entry_date'])); if ($heading_date_daily == $heading_flag_daily) { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_heading', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_heading', $tagdata); $heading_flag_daily = $heading_date_daily; } } } // END DATE HEADING // parse date footer if (strncmp($key, 'date_footer', 11) == 0) { // Set the display preference $display = (is_array($val) and isset($val['display'])) ? $val['display'] : 'daily'; // Hourly footer if ($display == 'hourly') { if (!isset($query_result[$row['count']]) or gmdate('YmdH', $this->EE->localize->set_localized_time($row['entry_date'])) != gmdate('YmdH', $this->EE->localize->set_localized_time($query_result[$row['count']]['entry_date']))) { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_footer', $tagdata); } else { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_footer', $tagdata); } } elseif ($display == 'weekly') { if (!isset($query_result[$row['count']]) or gmdate('YW', $this->EE->localize->set_localized_time($row['entry_date'])) != gmdate('YW', $this->EE->localize->set_localized_time($query_result[$row['count']]['entry_date']))) { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_footer', $tagdata); } else { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_footer', $tagdata); } } elseif ($display == 'monthly') { if (!isset($query_result[$row['count']]) or gmdate('Ym', $this->EE->localize->set_localized_time($row['entry_date'])) != gmdate('Ym', $this->EE->localize->set_localized_time($query_result[$row['count']]['entry_date']))) { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_footer', $tagdata); } else { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_footer', $tagdata); } } elseif ($display == 'yearly') { if (!isset($query_result[$row['count']]) or gmdate('Y', $this->EE->localize->set_localized_time($row['entry_date'])) != gmdate('Y', $this->EE->localize->set_localized_time($query_result[$row['count']]['entry_date']))) { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_footer', $tagdata); } else { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_footer', $tagdata); } } else { if (!isset($query_result[$row['count']]) or gmdate('Ymd', $this->EE->localize->set_localized_time($row['entry_date'])) != gmdate('Ymd', $this->EE->localize->set_localized_time($query_result[$row['count']]['entry_date']))) { $tagdata = $this->EE->TMPL->swap_var_pairs($key, 'date_footer', $tagdata); } else { $tagdata = $this->EE->TMPL->delete_var_pairs($key, 'date_footer', $tagdata); } } } // END DATE FOOTER } // END VARIABLE PAIRS // We swap out the conditionals after pairs are parsed so they don't interfere // with the string replace $tagdata = $this->EE->functions->prep_conditionals($tagdata, $cond); // Parse "single" variables foreach ($this->EE->TMPL->var_single as $key => $val) { /**-------- /** parse simple conditionals: {body|more|summary} /**--------*/ // Note: This must happen first. if (strpos($key, '|') !== FALSE && is_array($val)) { foreach ($val as $item) { // Basic fields if (isset($row[$item]) and $row[$item] != "") { $tagdata = $this->EE->TMPL->swap_var_single($key, $row[$item], $tagdata); continue; } // Custom channel fields if (isset($this->cfields[$row['site_id']][$item]) and isset($row['field_id_' . $this->cfields[$row['site_id']][$item]]) and $row['field_id_' . $this->cfields[$row['site_id']][$item]] != "") { $entry = $this->EE->typography->parse_type($row['field_id_' . $this->cfields[$row['site_id']][$item]], array('text_format' => $row['field_ft_' . $this->cfields[$row['site_id']][$item]], 'html_format' => $row['channel_html_formatting'], 'auto_links' => $row['channel_auto_link_urls'], 'allow_img_url' => $row['channel_allow_img_urls'])); $tagdata = $this->EE->TMPL->swap_var_single($key, $entry, $tagdata); continue; } } // Garbage collection $val = ''; $tagdata = $this->EE->TMPL->swap_var_single($key, "", $tagdata); } // parse {switch} variable if (preg_match("/^switch\\s*=.+/i", $key)) { $sparam = $this->EE->functions->assign_parameters($key); $sw = ''; if (isset($sparam['switch'])) { $sopt = explode("|", $sparam['switch']); $sw = $sopt[($count + count($sopt)) % count($sopt)]; } $tagdata = $this->EE->TMPL->swap_var_single($key, $sw, $tagdata); } // parse entry date if (isset($entry_date[$key])) { $val = str_replace($entry_date[$key], $this->EE->localize->convert_timestamp($entry_date[$key], $row['entry_date'], TRUE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } // Recent Comment Date if (isset($recent_comment_date[$key])) { if ($row['recent_comment_date'] != 0) { $val = str_replace($recent_comment_date[$key], $this->EE->localize->convert_timestamp($recent_comment_date[$key], $row['recent_comment_date'], TRUE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } else { $tagdata = str_replace(LD . $key . RD, '', $tagdata); } } // GMT date - entry date in GMT if (isset($gmt_entry_date[$key])) { $val = str_replace($gmt_entry_date[$key], $this->EE->localize->convert_timestamp($gmt_entry_date[$key], $row['entry_date'], FALSE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } if (isset($gmt_date[$key])) { $val = str_replace($gmt_date[$key], $this->EE->localize->convert_timestamp($gmt_date[$key], $row['entry_date'], FALSE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } // parse "last edit" date if (isset($edit_date[$key])) { $val = str_replace($edit_date[$key], $this->EE->localize->convert_timestamp($edit_date[$key], $this->EE->localize->timestamp_to_gmt($row['edit_date']), TRUE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } // "last edit" date as GMT if (isset($gmt_edit_date[$key])) { $val = str_replace($gmt_edit_date[$key], $this->EE->localize->convert_timestamp($gmt_edit_date[$key], $this->EE->localize->timestamp_to_gmt($row['edit_date']), FALSE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } // parse expiration date if (isset($expiration_date[$key])) { if ($row['expiration_date'] != 0) { $val = str_replace($expiration_date[$key], $this->EE->localize->convert_timestamp($expiration_date[$key], $row['expiration_date'], TRUE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } else { $tagdata = str_replace(LD . $key . RD, "", $tagdata); } } // "week_date" if (isset($week_date[$key])) { // Subtract the number of days the entry is "into" the week to get zero (Sunday) // If the entry date is for Sunday, and Monday is being used as the week's start day, // then we must back things up by six days $offset = 0; if (strtolower($this->EE->TMPL->fetch_param('start_day')) == 'monday') { $day_of_week = $this->EE->localize->convert_timestamp('%w', $row['entry_date'], TRUE); if ($day_of_week == '0') { $offset = -518400; // back six days } else { $offset = 86400; // plus one day } } $week_start_date = $row['entry_date'] - $this->EE->localize->convert_timestamp('%w', $row['entry_date'], TRUE) * 60 * 60 * 24 + $offset; $val = str_replace($week_date[$key], $this->EE->localize->convert_timestamp($week_date[$key], $week_start_date, TRUE), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } // parse profile path if (strncmp($key, 'profile_path', 12) == 0) { $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->functions->create_url($this->EE->functions->extract_path($key) . '/' . $row['member_id']), $tagdata); } // {member_search_path} if (strncmp($key, 'member_search_path', 18) == 0) { $tagdata = $this->EE->TMPL->swap_var_single($key, $search_link . $row['member_id'], $tagdata); } // parse comment_path if (strncmp($key, 'comment_path', 12) == 0 or strncmp($key, 'entry_id_path', 13) == 0) { $path = ($this->EE->functions->extract_path($key) != '' and $this->EE->functions->extract_path($key) != 'SITE_INDEX') ? $this->EE->functions->extract_path($key) . '/' . $row['entry_id'] : $row['entry_id']; $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->functions->create_url($path), $tagdata); } // parse URL title path if (strncmp($key, 'url_title_path', 14) == 0) { $path = ($this->EE->functions->extract_path($key) != '' and $this->EE->functions->extract_path($key) != 'SITE_INDEX') ? $this->EE->functions->extract_path($key) . '/' . $row['url_title'] : $row['url_title']; $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->functions->create_url($path), $tagdata); } // parse title permalink if (strncmp($key, 'title_permalink', 15) == 0) { $path = ($this->EE->functions->extract_path($key) != '' and $this->EE->functions->extract_path($key) != 'SITE_INDEX') ? $this->EE->functions->extract_path($key) . '/' . $row['url_title'] : $row['url_title']; $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->functions->create_url($path, FALSE), $tagdata); } // parse permalink if (strncmp($key, 'permalink', 9) == 0) { $path = ($this->EE->functions->extract_path($key) != '' and $this->EE->functions->extract_path($key) != 'SITE_INDEX') ? $this->EE->functions->extract_path($key) . '/' . $row['entry_id'] : $row['entry_id']; $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->functions->create_url($path, FALSE), $tagdata); } // {comment_auto_path} if ($key == "comment_auto_path") { $path = $row['comment_url'] == '' ? $row['channel_url'] : $row['comment_url']; $tagdata = $this->EE->TMPL->swap_var_single($key, $path, $tagdata); } // {comment_url_title_auto_path} if ($key == "comment_url_title_auto_path") { $path = $row['comment_url'] == '' ? $row['channel_url'] : $row['comment_url']; $tagdata = $this->EE->TMPL->swap_var_single($key, reduce_double_slashes($path . '/' . $row['url_title']), $tagdata); } // {comment_entry_id_auto_path} if ($key == "comment_entry_id_auto_path") { $path = $row['comment_url'] == '' ? $row['channel_url'] : $row['comment_url']; $tagdata = $this->EE->TMPL->swap_var_single($key, reduce_double_slashes($path . '/' . $row['entry_id']), $tagdata); } // {author} if ($key == "author") { $tagdata = $this->EE->TMPL->swap_var_single($val, $row['screen_name'] != '' ? $row['screen_name'] : $row['username'], $tagdata); } // {channel} if ($key == "channel") { $tagdata = $this->EE->TMPL->swap_var_single($val, $row['channel_title'], $tagdata); } // {channel_short_name} if ($key == "channel_short_name") { $tagdata = $this->EE->TMPL->swap_var_single($val, $row['channel_name'], $tagdata); } // {relative_date} if ($key == "relative_date") { $tagdata = $this->EE->TMPL->swap_var_single($val, $this->EE->localize->format_timespan($this->EE->localize->now - $row['entry_date']), $tagdata); } // {trimmed_url} - used by Atom feeds if ($key == "trimmed_url") { $channel_url = (isset($row['channel_url']) and $row['channel_url'] != '') ? $row['channel_url'] : ''; $channel_url = str_replace(array('http://', 'www.'), '', $channel_url); $xe = explode("/", $channel_url); $channel_url = current($xe); $tagdata = $this->EE->TMPL->swap_var_single($val, $channel_url, $tagdata); } // {relative_url} - used by Atom feeds if ($key == "relative_url") { $channel_url = (isset($row['channel_url']) and $row['channel_url'] != '') ? $row['channel_url'] : ''; $channel_url = str_replace('http://', '', $channel_url); if ($x = strpos($channel_url, "/")) { $channel_url = substr($channel_url, $x + 1); } $channel_url = rtrim($channel_url, '/'); $tagdata = $this->EE->TMPL->swap_var_single($val, $channel_url, $tagdata); } // {url_or_email} if ($key == "url_or_email") { $tagdata = $this->EE->TMPL->swap_var_single($val, $row['url'] != '' ? $row['url'] : $row['email'], $tagdata); } // {url_or_email_as_author} if ($key == "url_or_email_as_author") { $name = $row['screen_name'] != '' ? $row['screen_name'] : $row['username']; if ($row['url'] != '') { $tagdata = $this->EE->TMPL->swap_var_single($val, "<a href=\"" . $row['url'] . "\">" . $name . "</a>", $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_single($val, $this->EE->typography->encode_email($row['email'], $name), $tagdata); } } // {url_or_email_as_link} if ($key == "url_or_email_as_link") { if ($row['url'] != '') { $tagdata = $this->EE->TMPL->swap_var_single($val, "<a href=\"" . $row['url'] . "\">" . $row['url'] . "</a>", $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_single($val, $this->EE->typography->encode_email($row['email']), $tagdata); } } // {signature} if ($key == "signature") { if ($this->EE->session->userdata('display_signatures') == 'n' or $row['signature'] == '' or $this->EE->session->userdata('display_signatures') == 'n') { $tagdata = $this->EE->TMPL->swap_var_single($key, '', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->typography->parse_type($row['signature'], array('text_format' => 'xhtml', 'html_format' => 'safe', 'auto_links' => 'y', 'allow_img_url' => $this->EE->config->item('sig_allow_img_hotlink'))), $tagdata); } } if ($key == "signature_image_url") { if ($this->EE->session->userdata('display_signatures') == 'n' or $row['sig_img_filename'] == '' or $this->EE->session->userdata('display_signatures') == 'n') { $tagdata = $this->EE->TMPL->swap_var_single($key, '', $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('signature_image_width', '', $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('signature_image_height', '', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->config->slash_item('sig_img_url') . $row['sig_img_filename'], $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('signature_image_width', $row['sig_img_width'], $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('signature_image_height', $row['sig_img_height'], $tagdata); } } if ($key == "avatar_url") { if ($this->EE->session->userdata('display_avatars') == 'n' or $row['avatar_filename'] == '' or $this->EE->session->userdata('display_avatars') == 'n') { $tagdata = $this->EE->TMPL->swap_var_single($key, '', $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('avatar_image_width', '', $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('avatar_image_height', '', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->config->slash_item('avatar_url') . $row['avatar_filename'], $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('avatar_image_width', $row['avatar_width'], $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('avatar_image_height', $row['avatar_height'], $tagdata); } } if ($key == "photo_url") { if ($this->EE->session->userdata('display_photos') == 'n' or $row['photo_filename'] == '' or $this->EE->session->userdata('display_photos') == 'n') { $tagdata = $this->EE->TMPL->swap_var_single($key, '', $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('photo_image_width', '', $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('photo_image_height', '', $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_single($key, $this->EE->config->slash_item('photo_url') . $row['photo_filename'], $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('photo_image_width', $row['photo_width'], $tagdata); $tagdata = $this->EE->TMPL->swap_var_single('photo_image_height', $row['photo_height'], $tagdata); } } // parse {title} if ($key == 'title') { $row['title'] = str_replace(array('{', '}'), array('{', '}'), $row['title']); $tagdata = $this->EE->TMPL->swap_var_single($val, $this->EE->typography->format_characters($row['title']), $tagdata); } // parse basic fields (username, screen_name, etc.) // Use array_key_exists to handle null values if ($val and array_key_exists($val, $row)) { $tagdata = $this->EE->TMPL->swap_var_single($val, $row[$val], $tagdata); } // parse custom date fields if (isset($custom_date_fields[$key]) && isset($this->dfields[$row['site_id']])) { foreach ($this->dfields[$row['site_id']] as $dkey => $dval) { if (strncmp($key . ' ', $dkey . ' ', strlen($dkey . ' ')) !== 0) { continue; } if ($row['field_id_' . $dval] == 0 or $row['field_id_' . $dval] == '') { $tagdata = $this->EE->TMPL->swap_var_single($key, '', $tagdata); continue; } // use a temporary variable in case the custom date variable is used // multiple times with different formats; prevents localization from // occurring multiple times on the same value $temp_val = $row['field_id_' . $dval]; $localize = TRUE; if (isset($row['field_dt_' . $dval]) and $row['field_dt_' . $dval] != '') { $localize = TRUE; if ($row['field_dt_' . $dval] != '') { $temp_val = $this->EE->localize->simpl_offset($temp_val, $row['field_dt_' . $dval]); $localize = FALSE; } } $val = str_replace($custom_date_fields[$key], $this->EE->localize->convert_timestamp($custom_date_fields[$key], $temp_val, $localize), $val); $tagdata = $this->EE->TMPL->swap_var_single($key, $val, $tagdata); } } // Assign Related Entry IDs // When an entry has related entries within it, since the related entry ID // is stored in the custom field itself we need to pull it out and set it // aside so that when the related stuff is parsed out we'll have it. // We also need to modify the marker in the template so that we can replace // it with the right entry if (isset($this->rfields[$row['site_id']][$val])) { // No relationship? Ditch the marker if (!isset($row['field_id_' . $this->cfields[$row['site_id']][$val]]) or $row['field_id_' . $this->cfields[$row['site_id']][$val]] == 0 or !preg_match_all("/" . LD . "REL\\[" . $val . "\\](.+?)REL" . RD . "/", $tagdata, $match)) { // replace the marker with the {if no_related_entries} content preg_match_all("/" . LD . "REL\\[" . $val . "\\](.+?)REL" . RD . "/", $tagdata, $matches); foreach ($matches[1] as $match) { $tagdata = preg_replace("/" . LD . "REL\\[" . $val . "\\](.+?)REL" . RD . "/", $this->EE->TMPL->related_data[$match]['no_rel_content'], $tagdata); } } else { for ($j = 0; $j < count($match[1]); $j++) { $this->related_entries[] = $row['field_id_' . $this->cfields[$row['site_id']][$val]] . '_' . $match[1][$j]; $tagdata = preg_replace("/" . LD . "REL\\[" . $val . "\\](.+?)REL" . RD . "/", LD . "REL[" . $row['field_id_' . $this->cfields[$row['site_id']][$val]] . "][" . $val . "]\\1REL" . RD, $tagdata); } $tagdata = $this->EE->TMPL->swap_var_single($val, '', $tagdata); } } // Clean up any unparsed relationship fields if (isset($this->rfields[$row['site_id']]) && count($this->rfields[$row['site_id']]) > 0) { $tagdata = preg_replace("/" . LD . "REL\\[" . preg_quote($val, '/') . "\\](.+?)REL" . RD . "/", "", $tagdata); } // parse custom channel fields $params = array(); $parse_fnc = 'replace_tag'; $parse_fnc_catchall = 'replace_tag_catchall'; $replace = $key; if (($spc = strpos($key, ' ')) !== FALSE) { $params = $this->EE->functions->assign_parameters($key); $val = $key = substr($key, 0, $spc); } if (($cln = strpos($key, ':')) !== FALSE) { $modifier = substr($key, $cln + 1); $parse_fnc = 'replace_' . $modifier; $val = $key = substr($key, 0, $cln); } if (isset($this->cfields[$row['site_id']][$key])) { if (!isset($row['field_id_' . $this->cfields[$row['site_id']][$val]]) or $row['field_id_' . $this->cfields[$row['site_id']][$val]] == '') { $entry = ''; } else { $this->EE->load->library('api'); $this->EE->api->instantiate('channel_fields'); $field_id = $this->cfields[$row['site_id']][$key]; if ($this->EE->api_channel_fields->setup_handler($field_id)) { $this->EE->api_channel_fields->apply('_init', array(array('row' => $row))); $data = $this->EE->api_channel_fields->apply('pre_process', array($row['field_id_' . $field_id])); if ($this->EE->api_channel_fields->check_method_exists($parse_fnc)) { $entry = $this->EE->api_channel_fields->apply($parse_fnc, array($data, $params, FALSE)); } elseif ($this->EE->api_channel_fields->check_method_exists($parse_fnc_catchall)) { $entry = $this->EE->api_channel_fields->apply($parse_fnc_catchall, array($data, $params, FALSE, $modifier)); } else { $entry = ''; $this->EE->TMPL->log_item('Unable to find parse type for custom field: ' . $parse_fnc); } } else { // Couldn't find a fieldtype $entry = $this->EE->typography->parse_type($this->EE->functions->encode_ee_tags($row['field_id_' . $this->cfields[$row['site_id']][$val]]), array('text_format' => $row['field_ft_' . $this->cfields[$row['site_id']][$val]], 'html_format' => $row['channel_html_formatting'], 'auto_links' => $row['channel_auto_link_urls'], 'allow_img_url' => $row['channel_allow_img_urls'])); } } // prevent accidental parsing of other channel variables in custom field data if (strpos($entry, '{') !== FALSE) { $this->EE->load->helper('string'); $tagdata = $this->EE->TMPL->swap_var_single($replace, str_replace(array('{', '}'), array(unique_marker('channel_bracket_open'), unique_marker('channel_bracket_close')), $entry), $tagdata); } else { $tagdata = $this->EE->TMPL->swap_var_single($replace, $entry, $tagdata); } } // parse custom member fields if (isset($this->mfields[$val]) && array_key_exists('m_field_id_' . $value[0], $row)) { if (!isset($processed_member_fields[$row['member_id']]['m_field_id_' . $this->mfields[$val][0]])) { $processed_member_fields[$row['member_id']]['m_field_id_' . $this->mfields[$val][0]] = $this->EE->typography->parse_type($row['m_field_id_' . $this->mfields[$val][0]], array('text_format' => $this->mfields[$val][1], 'html_format' => 'safe', 'auto_links' => 'y', 'allow_img_url' => 'n')); } $tagdata = $this->EE->TMPL->swap_var_single($val, $processed_member_fields[$row['member_id']]['m_field_id_' . $this->mfields[$val][0]], $tagdata); } } // END SINGLE VARIABLES // do we need to replace any curly braces that we protected in custom fields? if (strpos($tagdata, unique_marker('channel_bracket_open')) !== FALSE) { $tagdata = str_replace(array(unique_marker('channel_bracket_open'), unique_marker('channel_bracket_close')), array('{', '}'), $tagdata); } // ------------------------------------------- // 'channel_entries_tagdata_end' hook. // - Take the final results of an entry's parsing and do what you wish // if ($this->EE->extensions->active_hook('channel_entries_tagdata_end') === TRUE) { $tagdata = $this->EE->extensions->call('channel_entries_tagdata_end', $tagdata, $row, $this); if ($this->EE->extensions->end_script === TRUE) { return $tagdata; } } // // ------------------------------------------- $this->return_data .= $tagdata; } // END FOREACH LOOP // Kill multi_field variable if (strpos($this->return_data, 'multi_field=') !== FALSE) { $this->return_data = preg_replace("/" . LD . "multi_field\\=[\"'](.+?)[\"']" . RD . "/s", "", $this->return_data); } // Do we have backspacing? if ($back = $this->EE->TMPL->fetch_param('backspace')) { if (is_numeric($back)) { $this->return_data = substr($this->return_data, 0, -$back); } } }
/** * Process Advanced Conditionals * * The syntax is generally: {if whatever = ""}Dude{if:elseif something != ""}Yo{if:else} * * The final processing of Advanced Conditionals. Takes all of the member variables and uncachable * variables and preps the conditionals with them. Then, it converts the conditionals to PHP so that * PHP can do all of the really heavy lifting for us. * * @param string * @return string */ public function advanced_conditionals($str) { if (stristr($str, LD . 'if') === FALSE) { return $str; } /* --------------------------------- /* Hidden Configuration Variables /* - protect_javascript => Prevents advanced conditional parser from processing anything in <script> tags /* ---------------------------------*/ if (ee()->config->item('protect_javascript') == 'n') { $this->protect_javascript = FALSE; } $user_vars = array('member_id', 'group_id', 'group_description', 'group_title', 'username', 'screen_name', 'email', 'ip_address', 'location', 'total_entries', 'total_comments', 'private_messages', 'total_forum_posts', 'total_forum_topics', 'total_forum_replies'); for ($i = 0, $s = count($user_vars), $data = array(); $i < $s; ++$i) { $data[$user_vars[$i]] = ee()->session->userdata[$user_vars[$i]]; $data['logged_in_' . $user_vars[$i]] = ee()->session->userdata[$user_vars[$i]]; } // Define an alternate variable for {group_id} since some tags use // it natively, causing it to be unavailable as a global $data['member_group'] = $data['logged_in_member_group'] = ee()->session->userdata['group_id']; // Logged in and logged out variables $data['logged_in'] = ee()->session->userdata['member_id'] == 0 ? 'FALSE' : 'TRUE'; $data['logged_out'] = ee()->session->userdata['member_id'] != 0 ? 'FALSE' : 'TRUE'; // current time $data['current_time'] = ee()->localize->now; // Member Group in_group('1') function, Super Secret! Shhhhh! if (preg_match_all("/in_group\\(([^\\)]+)\\)/", $str, $matches)) { $groups = is_array(ee()->session->userdata['group_id']) ? ee()->session->userdata['group_id'] : array(ee()->session->userdata['group_id']); for ($i = 0, $s = count($matches[0]); $i < $s; ++$i) { $check = explode('|', str_replace(array('"', "'"), '', $matches[1][$i])); $str = str_replace($matches[0][$i], count(array_intersect($check, $groups)) > 0 ? 'TRUE' : 'FALSE', $str); } } // Final Prep, Safety On $str = ee()->functions->prep_conditionals($str, array_merge($this->segment_vars, $this->embed_vars, ee()->config->_global_vars, $data), 'y'); // Protect Already Existing Unparsed PHP $opener = unique_marker('tmpl_php_open'); $closer = unique_marker('tmpl_php_close'); $str = str_replace(array('<?', '?' . '>'), array($opener . '?', '?' . $closer), $str); // Protect <script> tags $protected = array(); $front_protect = unique_marker('tmpl_script_open'); $back_protect = unique_marker('tmpl_script_close'); if ($this->protect_javascript !== FALSE && stristr($str, '<script') && preg_match_all("/<script.*?" . ">.*?<\\/script>/is", $str, $matches)) { for ($i = 0, $s = count($matches[0]); $i < $s; ++$i) { $protected[$front_protect . $i . $back_protect] = $matches[0][$i]; } $str = str_replace(array_values($protected), array_keys($protected), $str); } // Convert EE Conditionals to PHP $str = str_replace(array(LD . '/if' . RD, LD . 'if:else' . RD), array('<?php endif; ?' . '>', '<?php else : ?' . '>'), $str); if (strpos($str, LD . 'if') !== FALSE) { $str = preg_replace("/" . preg_quote(LD) . "((if:(else))*if)\\s+(.*?)" . preg_quote(RD) . "/s", '<?php \\3if(\\4) : ?' . '>', $str); } $str = $this->parse_template_php($str); // Unprotect <script> tags if (count($protected) > 0) { $str = str_replace(array_keys($protected), array_values($protected), $str); } // Unprotect Already Existing Unparsed PHP $str = str_replace(array($opener . '?', '?' . $closer), array('<' . '?', '?' . '>'), $str); return $str; }
/** * Display an RTE field * * @param string $data the RTE html content * @param string $field_name the field name for the RTE field * @param array $settings field settings: * field_ta_rows - the number of textarea rows * field_text_direction - ltr or rtl * field_fmt - xhtml, br or none * * @return string */ public function display_field($data, $field_name, $settings) { $this->EE->load->helper('form'); $field = array('name' => $field_name, 'id' => $field_name, 'rows' => $settings['field_ta_rows'], 'dir' => $settings['field_text_direction']); // form prepped nonsense $data = htmlspecialchars_decode($data, ENT_QUOTES); $code_marker = unique_marker('code'); $code_chunks = array(); $field_ft = isset($settings['field_fmt']) ? $settings['field_fmt'] : ''; if ($field_ft == 'xhtml') { $data = trim($data); // Undo any existing newline formatting. Typography will change // it anyways and the rtf will add its own. Having this here // prevents growing-newline syndrome in the rtf and lets us switch // between rtf and non-rtf. $data = preg_replace("/<\\/p>\n*<p>/is", "\n\n", $data); $data = preg_replace("/<br( \\/)?>\n/is", "\n", $data); } // remove code chunks if (preg_match_all("/\\[code\\](.+?)\\[\\/code\\]/si", $data, $matches)) { foreach ($matches[1] as $i => $chunk) { $code_chunks[] = trim($chunk); $data = str_replace($matches[0][$i], $code_marker . $i, $data); } } // Check the RTE module and user's preferences if ($this->EE->session->userdata('rte_enabled') == 'y' and $this->EE->config->item('rte_enabled') == 'y') { $field['class'] = 'WysiHat-field'; foreach ($code_chunks as &$chunk) { $chunk = htmlentities($chunk, ENT_QUOTES, 'UTF-8'); $chunk = str_replace("\n", '<br>', $chunk); } // xhtml vs br if ($settings['field_fmt'] == 'xhtml') { $this->EE->load->library('typography'); $data = $this->EE->typography->_format_newlines($data); // Remove double paragraph tags $data = preg_replace("/(<\\/?p>)\\1/is", "\\1", $data); } } // put code chunks back foreach ($code_chunks as $i => $chunk) { $data = str_replace($code_marker . $i, '[code]' . $chunk . '[/code]', $data); } // Swap {filedir_x} with the real URL. It will be converted back // upon submit by the RTE Image tool. $this->EE->load->model('file_upload_preferences_model'); $dirs = $this->EE->file_upload_preferences_model->get_file_upload_preferences($this->EE->session->userdata('group_id')); foreach ($dirs as $d) { // tag to replace $filedir = "{filedir_{$d['id']}}"; $data = str_replace($filedir, $d['url'], $data); } $data = htmlspecialchars($data, ENT_QUOTES); $field['value'] = $data; return form_textarea($field); }