mirror of https://github.com/IoTcat/ushio-img.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
580 lines
22 KiB
580 lines
22 KiB
<?php |
|
if (!defined('__TYPECHO_ROOT_DIR__')) exit; |
|
/** |
|
* 修改自 Wordpress 短代码API |
|
* 适用Typecho |
|
* |
|
* @author MaiCong |
|
* @link https://github.com/WordPress/WordPress/blob/master/wp-includes/shortcodes.php |
|
* @link https://maicong.me |
|
* @since 1.0.0 |
|
*/ |
|
|
|
$shortcode_tags = array(); |
|
|
|
function add_shortcode($tag, $func) |
|
{ |
|
global $shortcode_tags; |
|
if ('' == trim($tag)) { |
|
return; |
|
} |
|
if (0 !== preg_match('@[<>&/\[\]\x00-\x20=]@', $tag)) { |
|
return; |
|
} |
|
$shortcode_tags[$tag] = $func; |
|
} |
|
|
|
function do_shortcode($content, $ignore_html = false) |
|
{ |
|
global $shortcode_tags; |
|
if (false === strpos($content, '[')) { |
|
return $content; |
|
} |
|
if (empty($shortcode_tags) || !is_array($shortcode_tags)) { |
|
return $content; |
|
} |
|
//TODO |
|
// Find all registered tag names in $content. |
|
//20180603 |
|
$pregRule = "/<p>\[(.*?)\]<\/p>/"; |
|
$content = preg_replace($pregRule, '[${1}]', $content); |
|
|
|
preg_match_all('@\[([^<>&/\[\]\x00-\x20=]++)@', $content, $matches); |
|
$tagnames = array_intersect(array_keys($shortcode_tags), $matches[1]); |
|
if (empty($tagnames)) { |
|
return $content; |
|
} |
|
$content = do_shortcodes_in_html_tags($content, $ignore_html, $tagnames); |
|
$pattern = get_shortcode_regex($tagnames); |
|
$content = preg_replace_callback("/$pattern/", 'do_shortcode_tag', $content); |
|
// Always restore square braces so we don't break things like <!--[if IE ]> |
|
$content = strtr($content, array('[' => '[', ']' => ']')); |
|
return $content; |
|
} |
|
|
|
function do_shortcode_tag($m) |
|
{ |
|
global $shortcode_tags; |
|
// allow [[foo]] syntax for escaping a tag |
|
if ($m[1] == '[' && $m[6] == ']') { |
|
return substr($m[0], 1, -1); |
|
} |
|
$tag = $m[2]; |
|
$attr = shortcode_parse_atts($m[3]); |
|
if (!is_callable($shortcode_tags[$tag])) { |
|
/* translators: %s: shortcode tag */ |
|
return $m[0]; |
|
} |
|
if (isset($m[5])) { |
|
// enclosing tag - extra parameter |
|
return $m[1] . call_user_func($shortcode_tags[$tag], $attr, $m[5], $tag) . $m[6]; |
|
} else { |
|
// self-closing tag |
|
return $m[1] . call_user_func($shortcode_tags[$tag], $attr, null, $tag) . $m[6]; |
|
} |
|
} |
|
|
|
function shortcode_atts($pairs, $atts) |
|
{ |
|
$atts = (array) $atts; |
|
$out = array(); |
|
foreach ($pairs as $name => $default) { |
|
if (array_key_exists($name, $atts)) { |
|
$out[$name] = $atts[$name]; |
|
} else { |
|
$out[$name] = $default; |
|
} |
|
|
|
} |
|
return $out; |
|
} |
|
|
|
function shortcode_parse_atts($text) |
|
{ |
|
$atts = array(); |
|
$pattern = '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; |
|
$text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text); |
|
if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) { |
|
foreach ($match as $m) { |
|
if (!empty($m[1])) { |
|
$atts[strtolower($m[1])] = stripcslashes($m[2]); |
|
} elseif (!empty($m[3])) { |
|
$atts[strtolower($m[3])] = stripcslashes($m[4]); |
|
} elseif (!empty($m[5])) { |
|
$atts[strtolower($m[5])] = stripcslashes($m[6]); |
|
} elseif (isset($m[7]) && strlen($m[7])) { |
|
$atts[] = stripcslashes($m[7]); |
|
} elseif (isset($m[8])) { |
|
$atts[] = stripcslashes($m[8]); |
|
} |
|
|
|
} |
|
// Reject any unclosed HTML elements |
|
foreach ($atts as &$value) { |
|
if (false !== strpos($value, '<')) { |
|
if (1 !== preg_match('/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value)) { |
|
$value = ''; |
|
} |
|
} |
|
} |
|
} else { |
|
$atts = ltrim($text); |
|
} |
|
return $atts; |
|
} |
|
|
|
function get_shortcode_regex($tagnames = null) |
|
{ |
|
global $shortcode_tags; |
|
if (empty($tagnames)) { |
|
$tagnames = array_keys($shortcode_tags); |
|
} |
|
$tagregexp = join('|', array_map('preg_quote', $tagnames)); |
|
// WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag() |
|
// Also, see shortcode_unautop() and shortcode.js. |
|
return |
|
'\\[' // Opening bracket |
|
. '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]] |
|
. "($tagregexp)"// 2: Shortcode name |
|
. '(?![\\w-])' // Not followed by word character or hyphen |
|
. '(' // 3: Unroll the loop: Inside the opening shortcode tag |
|
. '[^\\]\\/]*' // Not a closing bracket or forward slash |
|
. '(?:' |
|
. '\\/(?!\\])' // A forward slash not followed by a closing bracket |
|
. '[^\\]\\/]*' // Not a closing bracket or forward slash |
|
. ')*?' |
|
. ')' |
|
. '(?:' |
|
. '(\\/)' // 4: Self closing tag ... |
|
. '\\]' // ... and closing bracket |
|
. '|' |
|
. '\\]' // Closing bracket |
|
. '(?:' |
|
. '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags |
|
. '[^\\[]*+' // Not an opening bracket |
|
. '(?:' |
|
. '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag |
|
. '[^\\[]*+' // Not an opening bracket |
|
. ')*+' |
|
. ')' |
|
. '\\[\\/\\2\\]' // Closing shortcode tag |
|
. ')?' |
|
. ')' |
|
. '(\\]?)'; // 6: Optional second closing brocket for escaping shortcodes: [[tag]] |
|
} |
|
|
|
function do_shortcodes_in_html_tags($content, $ignore_html, $tagnames) |
|
{ |
|
// Normalize entities in unfiltered HTML before adding placeholders. |
|
$trans = array('[' => '[', ']' => ']'); |
|
$content = strtr($content, $trans); |
|
$trans = array('[' => '[', ']' => ']'); |
|
$pattern = get_shortcode_regex($tagnames); |
|
$textarr = html_split($content); |
|
foreach ($textarr as &$element) { |
|
if ('' == $element || '<' !== $element[0]) { |
|
continue; |
|
} |
|
$noopen = false === strpos($element, '['); |
|
$noclose = false === strpos($element, ']'); |
|
if ($noopen || $noclose) { |
|
// This element does not contain shortcodes. |
|
if ($noopen xor $noclose) { |
|
// Need to encode stray [ or ] chars. |
|
$element = strtr($element, $trans); |
|
} |
|
continue; |
|
} |
|
if ($ignore_html || '<!--' === substr($element, 0, 4) || '<![CDATA[' === substr($element, 0, 9)) { |
|
// Encode all [ and ] chars. |
|
$element = strtr($element, $trans); |
|
continue; |
|
} |
|
$attributes = kses_attr_parse($element); |
|
if (false === $attributes) { |
|
// Some plugins are doing things like [name] <[email]>. |
|
if (1 === preg_match('%^<\s*\[\[?[^\[\]]+\]%', $element)) { |
|
$element = preg_replace_callback("/$pattern/", 'do_shortcode_tag', $element); |
|
} |
|
// Looks like we found some crazy unfiltered HTML. Skipping it for sanity. |
|
$element = strtr($element, $trans); |
|
continue; |
|
} |
|
// Get element name |
|
$front = array_shift($attributes); |
|
$back = array_pop($attributes); |
|
$matches = array(); |
|
preg_match('%[a-zA-Z0-9]+%', $front, $matches); |
|
$elname = $matches[0]; |
|
// Look for shortcodes in each attribute separately. |
|
foreach ($attributes as &$attr) { |
|
$open = strpos($attr, '['); |
|
$close = strpos($attr, ']'); |
|
if (false === $open || false === $close) { |
|
continue; // Go to next attribute. Square braces will be escaped at end of loop. |
|
} |
|
$double = strpos($attr, '"'); |
|
$single = strpos($attr, "'"); |
|
if ((false === $single || $open < $single) && (false === $double || $open < $double)) { |
|
// $attr like '[shortcode]' or 'name = [shortcode]' implies unfiltered_html. |
|
// In this specific situation we assume KSES did not run because the input |
|
// was written by an administrator, so we should avoid changing the output |
|
// and we do not need to run KSES here. |
|
$attr = preg_replace_callback("/$pattern/", 'do_shortcode_tag', $attr); |
|
} else { |
|
// $attr like 'name = "[shortcode]"' or "name = '[shortcode]'" |
|
// We do not know if $content was unfiltered. Assume KSES ran before shortcodes. |
|
$count = 0; |
|
$new_attr = preg_replace_callback("/$pattern/", 'do_shortcode_tag', $attr, -1, $count); |
|
if ($count > 0) { |
|
// Sanitize the shortcode output using KSES. |
|
$new_attr = kses_one_attr($new_attr, $elname); |
|
if ('' !== trim($new_attr)) { |
|
// The shortcode is safe to use now. |
|
$attr = $new_attr; |
|
} |
|
} |
|
} |
|
} |
|
$element = $front . implode('', $attributes) . $back; |
|
// Now encode any remaining [ or ] chars. |
|
$element = strtr($element, $trans); |
|
} |
|
$content = implode('', $textarr); |
|
return $content; |
|
} |
|
|
|
function html_split($input) |
|
{ |
|
return preg_split(get_html_split_regex(), $input, -1, PREG_SPLIT_DELIM_CAPTURE); |
|
} |
|
|
|
function get_html_split_regex() |
|
{ |
|
static $regex; |
|
if (!isset($regex)) { |
|
$comments = |
|
'!' // Start of comment, after the <. |
|
. '(?:' // Unroll the loop: Consume everything until --> is found. |
|
. '-(?!->)' // Dash not followed by end of comment. |
|
. '[^\-]*+' // Consume non-dashes. |
|
. ')*+' // Loop possessively. |
|
. '(?:-->)?'; // End of comment. If not found, match all input. |
|
$cdata = |
|
'!\[CDATA\[' // Start of comment, after the <. |
|
. '[^\]]*+' // Consume non-]. |
|
. '(?:' // Unroll the loop: Consume everything until ]]> is found. |
|
. '](?!]>)' // One ] not followed by end of comment. |
|
. '[^\]]*+' // Consume non-]. |
|
. ')*+' // Loop possessively. |
|
. '(?:]]>)?'; // End of comment. If not found, match all input. |
|
$escaped = |
|
'(?=' // Is the element escaped? |
|
. '!--' |
|
. '|' |
|
. '!\[CDATA\[' |
|
. ')' |
|
. '(?(?=!-)' // If yes, which type? |
|
. $comments |
|
. '|' |
|
. $cdata |
|
. ')'; |
|
$regex = |
|
'/(' // Capture the entire match. |
|
. '<' // Find start of element. |
|
. '(?' // Conditional expression follows. |
|
. $escaped // Find end of escaped element. |
|
. '|' // ... else ... |
|
. '[^>]*>?' // Find end of normal element. |
|
. ')' |
|
. ')/'; |
|
} |
|
return $regex; |
|
} |
|
|
|
function kses_attr_parse($element) |
|
{ |
|
$valid = preg_match('%^(<\s*)(/\s*)?([a-zA-Z0-9]+\s*)([^>]*)(>?)$%', $element, $matches); |
|
if (1 !== $valid) { |
|
return false; |
|
} |
|
$begin = $matches[1]; |
|
$slash = $matches[2]; |
|
$elname = $matches[3]; |
|
$attr = $matches[4]; |
|
$end = $matches[5]; |
|
if ('' !== $slash) { |
|
// Closing elements do not get parsed. |
|
return false; |
|
} |
|
// Is there a closing XHTML slash at the end of the attributes? |
|
if (1 === preg_match('%\s*/\s*$%', $attr, $matches)) { |
|
$xhtml_slash = $matches[0]; |
|
$attr = substr($attr, 0, -strlen($xhtml_slash)); |
|
} else { |
|
$xhtml_slash = ''; |
|
} |
|
|
|
// Split it |
|
$attrarr = kses_hair_parse($attr); |
|
if (false === $attrarr) { |
|
return false; |
|
} |
|
// Make sure all input is returned by adding front and back matter. |
|
array_unshift($attrarr, $begin . $slash . $elname); |
|
array_push($attrarr, $xhtml_slash . $end); |
|
|
|
return $attrarr; |
|
} |
|
|
|
function kses_hair_parse($attr) |
|
{ |
|
if ('' === $attr) { |
|
return array(); |
|
} |
|
$regex = |
|
'(?:' |
|
. '[-a-zA-Z:]+' // Attribute name. |
|
. '|' |
|
. '\[\[?[^\[\]]+\]\]?' // Shortcode in the name position implies unfiltered_html. |
|
. ')' |
|
. '(?:' // Attribute value. |
|
. '\s*=\s*' // All values begin with '=' |
|
. '(?:' |
|
. '"[^"]*"' // Double-quoted |
|
. '|' |
|
. "'[^']*'" // Single-quoted |
|
. '|' |
|
. '[^\s"\']+' // Non-quoted |
|
. '(?:\s|$)' // Must have a space |
|
. ')' |
|
. '|' |
|
. '(?:\s|$)' // If attribute has no value, space is required. |
|
. ')' |
|
. '\s*'; // Trailing space is optional except as mentioned above. |
|
// Although it is possible to reduce this procedure to a single regexp, |
|
// we must run that regexp twice to get exactly the expected result. |
|
$validation = "%^($regex)+$%"; |
|
$extraction = "%$regex%"; |
|
if (1 === preg_match($validation, $attr)) { |
|
preg_match_all($extraction, $attr, $attrarr); |
|
return $attrarr[0]; |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
function kses_one_attr($string, $element) |
|
{ |
|
$string = preg_replace(['/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '%&\s*\{[^}]*(\}\s*;?|$)%'], '', $string); |
|
|
|
// Preserve leading and trailing whitespace. |
|
$matches = array(); |
|
preg_match('/^\s*/', $string, $matches); |
|
$lead = $matches[0]; |
|
preg_match('/\s*$/', $string, $matches); |
|
$trail = $matches[0]; |
|
if (empty($trail)) { |
|
$string = substr($string, strlen($lead)); |
|
} else { |
|
$string = substr($string, strlen($lead), -strlen($trail)); |
|
} |
|
|
|
// Parse attribute name and value from input. |
|
$split = preg_split('/\s*=\s*/', $string, 2); |
|
$name = $split[0]; |
|
if (count($split) == 2) { |
|
$value = $split[1]; |
|
// Remove quotes surrounding $value. |
|
// Also guarantee correct quoting in $string for this one attribute. |
|
if ('' == $value) { |
|
$quote = ''; |
|
} else { |
|
$quote = $value[0]; |
|
} |
|
if ('"' == $quote || "'" == $quote) { |
|
if (substr($value, -1) != $quote) { |
|
return ''; |
|
} |
|
$value = substr($value, 1, -1); |
|
} else { |
|
$quote = '"'; |
|
} |
|
// Sanitize quotes, angle braces, and entities. |
|
$value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); |
|
// Sanitize URI values. |
|
$string = "$name=$quote$value$quote"; |
|
$vless = 'n'; |
|
} else { |
|
$value = ''; |
|
$vless = 'y'; |
|
} |
|
|
|
// Restore whitespace. |
|
return $lead . $string . $trail; |
|
} |
|
|
|
function autop($pee, $br = true) |
|
{ |
|
$pre_tags = array(); |
|
if (trim($pee) === '') { |
|
return ''; |
|
} |
|
// Just to make things a little easier, pad the end. |
|
$pee = $pee . "\n"; |
|
/* |
|
* Pre tags shouldn't be touched by autop. |
|
* Replace pre tags with placeholders and bring them back after autop. |
|
*/ |
|
if (strpos($pee, '<pre') !== false) { |
|
$pee_parts = explode('</pre>', $pee); |
|
$last_pee = array_pop($pee_parts); |
|
$pee = ''; |
|
$i = 0; |
|
foreach ($pee_parts as $pee_part) { |
|
$start = strpos($pee_part, '<pre'); |
|
// Malformed html? |
|
if ($start === false) { |
|
$pee .= $pee_part; |
|
continue; |
|
} |
|
$name = "<pre wp-pre-tag-$i></pre>"; |
|
$pre_tags[$name] = substr($pee_part, $start) . '</pre>'; |
|
$pee .= substr($pee_part, 0, $start) . $name; |
|
$i++; |
|
} |
|
$pee .= $last_pee; |
|
} |
|
// Change multiple <br>s into two line breaks, which will turn into paragraphs. |
|
$pee = preg_replace('|<br\s*/?>\s*<br\s*/?>|', "\n\n", $pee); |
|
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)'; |
|
// Add a double line break above block-level opening tags. |
|
$pee = preg_replace('!(<' . $allblocks . '[\s/>])!', "\n\n$1", $pee); |
|
// Add a double line break below block-level closing tags. |
|
$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee); |
|
// Standardize newline characters to "\n". |
|
$pee = str_replace(array("\r\n", "\r"), "\n", $pee); |
|
// Find newlines in all elements and add placeholders. |
|
$pee = replace_in_html_tags($pee, array("\n" => ' <!-- wpnl --> ')); |
|
// Collapse line breaks before and after <option> elements so they don't get autop'd. |
|
if (strpos($pee, '<option') !== false) { |
|
$pee = preg_replace('|\s*<option|', '<option', $pee); |
|
$pee = preg_replace('|</option>\s*|', '</option>', $pee); |
|
} |
|
/* |
|
* Collapse line breaks inside <object> elements, before <param> and <embed> elements |
|
* so they don't get autop'd. |
|
*/ |
|
if (strpos($pee, '</object>') !== false) { |
|
$pee = preg_replace('|(<object[^>]*>)\s*|', '$1', $pee); |
|
$pee = preg_replace('|\s*</object>|', '</object>', $pee); |
|
$pee = preg_replace('%\s*(</?(?:param|embed)[^>]*>)\s*%', '$1', $pee); |
|
} |
|
/* |
|
* Collapse line breaks inside <audio> and <video> elements, |
|
* before and after <source> and <track> elements. |
|
*/ |
|
if (strpos($pee, '<source') !== false || strpos($pee, '<track') !== false) { |
|
$pee = preg_replace('%([<\[](?:audio|video)[^>\]]*[>\]])\s*%', '$1', $pee); |
|
$pee = preg_replace('%\s*([<\[]/(?:audio|video)[>\]])%', '$1', $pee); |
|
$pee = preg_replace('%\s*(<(?:source|track)[^>]*>)\s*%', '$1', $pee); |
|
} |
|
// Collapse line breaks before and after <figcaption> elements. |
|
if (strpos($pee, '<figcaption') !== false) { |
|
$pee = preg_replace('|\s*(<figcaption[^>]*>)|', '$1', $pee); |
|
$pee = preg_replace('|</figcaption>\s*|', '</figcaption>', $pee); |
|
} |
|
// Remove more than two contiguous line breaks. |
|
$pee = preg_replace("/\n\n+/", "\n\n", $pee); |
|
// Split up the contents into an array of strings, separated by double line breaks. |
|
$pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY); |
|
// Reset $pee prior to rebuilding. |
|
$pee = ''; |
|
// Rebuild the content as a string, wrapping every bit with a <p>. |
|
foreach ($pees as $tinkle) { |
|
$pee .= '<p>' . trim($tinkle, "\n") . "</p>\n"; |
|
} |
|
// Under certain strange conditions it could create a P of entirely whitespace. |
|
$pee = preg_replace('|<p>\s*</p>|', '', $pee); |
|
// Add a closing <p> inside <div>, <address>, or <form> tag if missing. |
|
$pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', '<p>$1</p></$2>', $pee); |
|
// If an opening or closing block element tag is wrapped in a <p>, unwrap it. |
|
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee); |
|
// In some cases <li> may get wrapped in <p>, fix them. |
|
$pee = preg_replace('|<p>(<li.+?)</p>|', '$1', $pee); |
|
// If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>. |
|
$pee = preg_replace('|<p><blockquote([^>]*)>|i', '<blockquote$1><p>', $pee); |
|
$pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee); |
|
// If an opening or closing block element tag is preceded by an opening <p> tag, remove it. |
|
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', '$1', $pee); |
|
// If an opening or closing block element tag is followed by a closing <p> tag, remove it. |
|
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', '$1', $pee); |
|
// Optionally insert line breaks. |
|
if ($br) { |
|
// Replace newlines that shouldn't be touched with a placeholder. |
|
$pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee); |
|
// Normalize <br> |
|
$pee = str_replace(array('<br>', '<br/>'), '<br />', $pee); |
|
// Replace any new line characters that aren't preceded by a <br /> with a <br />. |
|
$pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); |
|
// Replace newline placeholders with newlines. |
|
$pee = str_replace('<PreserveNewline />', "\n", $pee); |
|
} |
|
// If a <br /> tag is after an opening or closing block tag, remove it. |
|
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', '$1', $pee); |
|
// If a <br /> tag is before a subset of opening or closing block tags, remove it. |
|
$pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee); |
|
$pee = preg_replace("|\n</p>$|", '</p>', $pee); |
|
// Replace placeholder <pre> tags with their original content. |
|
if (!empty($pre_tags)) { |
|
$pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee); |
|
} |
|
// Restore newlines in all elements. |
|
if (false !== strpos($pee, '<!-- wpnl -->')) { |
|
$pee = str_replace(array(' <!-- wpnl --> ', '<!-- wpnl -->'), "\n", $pee); |
|
} |
|
return $pee; |
|
} |
|
|
|
function _autop_newline_preservation_helper($matches) |
|
{ |
|
return str_replace("\n", '<PreserveNewline />', $matches[0]); |
|
} |
|
|
|
function replace_in_html_tags($haystack, $replace_pairs) |
|
{ |
|
// Find all elements. |
|
$textarr = html_split($haystack); |
|
$changed = false; |
|
// Optimize when searching for one item. |
|
if (1 === count($replace_pairs)) { |
|
// Extract $needle and $replace. |
|
foreach ($replace_pairs as $needle => $replace) { |
|
} |
|
// Loop through delimiters (elements) only. |
|
for ($i = 1, $c = count($textarr); $i < $c; $i += 2) { |
|
if (false !== strpos($textarr[$i], $needle)) { |
|
$textarr[$i] = str_replace($needle, $replace, $textarr[$i]); |
|
$changed = true; |
|
} |
|
} |
|
} else { |
|
// Extract all $needles. |
|
$needles = array_keys($replace_pairs); |
|
// Loop through delimiters (elements) only. |
|
for ($i = 1, $c = count($textarr); $i < $c; $i += 2) { |
|
foreach ($needles as $needle) { |
|
if (false !== strpos($textarr[$i], $needle)) { |
|
$textarr[$i] = strtr($textarr[$i], $replace_pairs); |
|
$changed = true; |
|
// After one strtr() break out of the foreach loop and look at next element. |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
if ($changed) { |
|
$haystack = implode($textarr); |
|
} |
|
return $haystack; |
|
}
|
|
|