around the generated // line. this is useful for making html of headlines and titles. as it is not too // handy to have

inside your

// function any_wiki_tohtml ( $s, $options = array() ) { list($tk, $tk_s) = wiki_tokenizer($s, $options); $block = array(); // lines for current block $line = array(); // stacked tokens for current line $line_s = array(); // stacked texts for current line $html = ''; // generated html $i = 0; $toc = false; // is there a toc or not? do { $tok = $tk[$i]; switch ($tok) { case 'br': $line[] = 'html'; $line_s[] = "
\n"; break; case 'html': list($_html, $block) = _wiki_reduce_line($block, $line, $line_s); $html .= $_html . _wiki_reduce_block($block); if (wiki_allow_html()) { $html .= "\n" . $tk_s[$i] . "\n"; } else { $html .= '

' . nl2br(strip_tags($tk_s[$i])) . '

'; } $line = array(); $line_s = array(); $block = array(); break; case 'code': list($_html, $block) = _wiki_reduce_line($block, $line, $line_s); $html .= $_html . _wiki_reduce_block($block); $html .= "\n
\n" . htmlspecialchars($tk_s[$i]) . "
\n"; $line = array(); $line_s = array(); $block = array(); break; case 'p': case 'end': list($_html, $block) = _wiki_reduce_line($block, $line, $line_s); $html .= $_html . "\n" . _wiki_reduce_block($block); $line = array(); $line_s = array(); $block = array(); break; case 'newline': list($_html, $block) = _wiki_reduce_line($block, $line, $line_s); $html .= $_html; $line = array(); $line_s = array(); break; case 'toc': $html .= ''; $line = array(); $line_s = array(); $toc = true; break; case 'comment': if ($i == 0) { // Comment at the start of a line or in a block $html .= ''; } else { // Comment in a line list($line, $line_s) = _wiki_shift_reduce($line, $line_s, $tok, $tk_s[$i]); } break; case 'word': case ' ': default: list($line, $line_s) = _wiki_shift_reduce($line, $line_s, $tok, $tk_s[$i]); break; } $i++; } while ($tok != 'end'); // Merge

's over more than one line $html = preg_replace("|

\n

|", "
\n", $html); //PH: \-newline to "skip" newlining. $html = preg_replace("|\\\\
|", "", $html); if (!empty($options['target']) && $options['target'] == 'line') { // Strip the

tags... the user wants a single line. $html = trim(preg_replace('||', ' ', $html)); } else if ($toc) { $html = _wiki_toc($html); } return trim($html); } // Function: wiki_allow_html // Access: EXTERNAL // Parameters: - // Returns: false no html allowed // true html allowed // Description: Check if the ACL allows html entry // function wiki_allow_html ( ) { $allow = false; if (isset($GLOBALS['any_acl'])) { $allow = $GLOBALS['any_acl']->allowHtml(); } return $allow; } // Function: wiki_filter_uri // Access: EXTERNAL // Parameters: $uri uri to be checked // Returns: false when uri not allowed // uri when allowed // Description: Check if the ACL allows the given uri // function wiki_filter_uri ( $uri ) { if (isset($GLOBALS['any_acl'])) { $uri = $GLOBALS['any_acl']->filterUri($uri); } return $uri; } // Function: wiki_filter_attrs // Access: EXTERNAL // Parameters: $uri uri to be checked // Returns: false when uri not allowed // uri when allowed // Description: Check if the ACL allows the given attrs. // This function has a short whitelist of allowed attributes. // function wiki_filter_attrs ( $attr ) { $as = array(); foreach ($attr as $a => $v) { switch ($a) { case 'id': case 'name': case 'align': case 'valign': case 'title': case 'width': case 'height': case 'rel': case 'alt': case 'class': case 'link': case 'caption': $as[$a] = $v; break; default: if ( isset($GLOBALS['any_acl']) && $GLOBALS['any_acl']->allowHtml()) { $as[$a] = $v; } break; } } return $as; } // Function: _wiki_reduce_block // Access: INTERNAL // Parameters: $block the tokens in the block // Returns: html fragment // Description: Force the complete reduction of a block to html // function _wiki_reduce_block ( $block ) { if (count($block) > 0) { list($html, $block) = _wiki_shift_reduce_block($block, array('end'), array('')); } else { $html = ''; } return $html; } // Function: _wiki_shift_reduce_block // Access: INTERNAL // Parameters: $block the tokens in the block // $line line tokens // $line_s line strings // Returns: array(html-fragment, block) // Description: (Partially) reduces the block after encountering the given line // // Checks for: // - enumerated lists // - tables // - blockquote // // // Each block entry is as follows: // // ( class, depth, class-parms, line_tokens, line_strings ) // // Where class is one of: // // table, ul, ol, blockquote, dl // // Depth is valid for: // // ul, ol, blockqoute // function _wiki_shift_reduce_block ( $block, $line, $line_s ) { if (!empty($line)) { if ($line[0] == '=' && @$line[1] == ' ') { $html = _wiki_reduce_block($block); list($line, $line_s) = _wiki_merge($line, $line_s, 2, false, true); $html .= "\n

" . $line_s[2] . "

\n"; return array($html, array()); } } $block_line = _wiki_block_line($line, $line_s); if ($block_line[0] == 'p' || $block_line[0] == 'end') { $html = _wiki_reduce_block_lines($block); if ($block_line[0] == 'p') { list($line, $line_s) = _wiki_merge($line, $line_s, 0, false, true); if (!empty($line_s[0])) { $html .= "

" . $line_s[0] . "

\n"; } } $block = array(); } else { $block[] = $block_line; $html = ''; } return array($html, $block); } // Function: _wiki_reduce_block_lines // Access: INTERNAL // Parameters: $block a complete block // Returns: html // Description: recursively reduces a block to html // all line level reductions have been done // what we get is a block of lines, each preparsed. // function _wiki_reduce_block_lines ( &$block ) { if (empty($block)) { return ''; } $len = count($block); $class = $block[0][0]; $depth = $block[0][1]; // Collect all lines with the same class and depth $sub_block = array(); $sub_block[] = array_shift($block); if ($class == 'ol') { $alt_class = 'ul'; } else if ($class == 'ul') { $alt_class = 'ol'; } else { $alt_class = false; } while ( !empty($block) && $block[0][1] >= $depth && ( $block[0][0] == $class || $block[0][0] == $alt_class)) { if ($block[0][1] > $depth || $block[0][0] != $class) { // this is a nested block of the same kind // reduce this one separately and remember the html in the previous block line $html = _wiki_reduce_block_lines($block); if (!empty($html)) { $sub_block[count($sub_block)-1][5] = $html; } } else { $sub_block[] = array_shift($block); } } // special handling for a table $td = 0; if ($class == 'table') { foreach ($sub_block as $sub) { $td = max($td, $sub[2]); } } // generate the html for the captured block $html = "<$class>\n"; $nr = 0; foreach ($sub_block as $sub) { $pars = $sub[2]; $line = $sub[3]; $line_s = $sub[4]; $nested = isset($sub[5]) ? $sub[5] : ''; $nr++; switch ($class) { case 'ol': case 'ul': list($line, $line_s) = _wiki_merge($line, $line_s, 2, false, true); $html .= '
  • ' . trim($line_s[2]) . $nested . "
  • \n"; break; case 'table': // Generate a row $html .= _wiki_table_row($td, $line, $line_s, $pars); break; case 'blockquote': if ($nr == 1) { $html .= '

    '; } list($line, $line_s) = _wiki_merge($line, $line_s, 2, false, true); $html .= $line_s[2] . $nested; if ($nr != count($sub_block)) { $html .= '
    '; } else { $html .= "

    \n"; } break; case 'dl': // $pars is the offset of the first ' ' of the ' : ' separating the dt from the dd list($line, $line_s) = _wiki_merge($line, $line_s, $pars+3, false, true); // the reduced html of the dd $dd = array_pop($line_s); array_pop($line); // op the ' ' ':' ' '; array_pop($line_s); array_pop($line); array_pop($line_s); array_pop($line); array_pop($line_s); array_pop($line); // Reduce the dt part list($line, $line_s) = _wiki_merge($line, $line_s, 2, false, true); $dt = array_pop($line_s); $html .= "
    $dt
    \n
    $dd
    \n"; break; } } $html .= "\n\n"; return $html; } // Function: _wiki_table_row // Access: INTERNAL // Parameters: $table_cols nr of tds // $line tokens in line // $line_s text of tokens // Returns: html for row // Description: generates the html for a row // function _wiki_table_row ( $table_cols, $line, $line_s ) { $html = ""; $len = count($line); $td = array(); $start = 1; $colspan= 1; // Split the line in tds for ($i=1;$i<$len;$i++) { if ($line[$i] == '||') { if ($line[$i-1] == '||' && $i+1 < $len) { $colspan++; $start++; } else { // A td from $start to $i-1 if ($i - $start > 0) { $td[] = array( array_slice($line, $start, $i - $start), array_slice($line_s, $start, $i - $start), $colspan); } else { $td[] = array(false, false, $colspan); } $start = $i+1; $colspan = 1; } } } // Generate the html per td foreach ($td as $t) { $line = $t[0]; $line_s = $t[1]; if ($t[2] > 1) { $colspan = ' colspan="' . $t[2] . '" '; } else { $colspan = ''; } if (!empty($line)) { $end = ""; switch ($line[0]) { case '>': $html .= "\n "; $start = 1; break; case '<': $html .= "\n "; $start = 1; break; case '=': $html .= "\n "; $start = 1; break; case '~': $html .= "\n "; $end = ""; $start = 1; break; default: $html .= "\n "; $start = 0; break; } list($line, $line_s) = _wiki_merge($line, $line_s, $start, false, true); $html .= trim($line_s[$start]) . $end; } else { $html .= "\n "; } } $html .= "\n\n"; return $html; } // Function: _wiki_block_line // Access: INTERNAL // Parameters: $line line tokens // $line_s line strings // Returns: a block line entry // Description: checks the line to see what kind of block line the line is // function _wiki_block_line ( $line, $line_s ) { $len = count($line); if ($len >= 2) { // : term : definition if ( $line[0] == ':' && $line[1] == ' ') { // Try to find (' ', ':' , ' '); $i = 2; $offs = false; while ($i < $len - 2 && $offs === false) { if ($line[$i] == ':' && $line[$i-1] == ' ' && $line[$i+1] == ' ') { $offs = $i-1; } $i++; } if ($offs !== false) { return array('dl', 0, $offs, $line, $line_s); } } // || td || .. || if ($line[0] == '||' && $line[$len-1] == '||') { // count the number of cols $cols = 0; for ($i = 0; $i<$len; $i++) { if ($line[$i] == '||') { $cols++; } } return array('table', 0, $cols-1, $line, $line_s); } // > block quoted text if ($line[0] == '>' && $line[1] == ' ') { return array('blockquote', strlen($line_s[0]), 0, $line, $line_s); } // * unordered list if ($line[0] == '*' && $line[1] == ' ') { return array('ul', 0, 0, $line, $line_s); } if ($line[0] == ' ' && $line[1] == '*' && $line[2] == ' ') { return array('ul', strlen($line_s[0]), 0, $line, $line_s); } // # ordered list if ($line[0] == '#' && $line[1] == ' ') { return array('ol', 0, 0, $line, $line_s); } if ($line[0] == ' ' && $line[1] == '#' && $len > 2 && $line[2] == ' ') { return array('ol', strlen($line_s[0]), 0, $line, $line_s); } } // Just another part of a paragraph if ($len > 0 && $line[0] == 'end') { return array('end', 0, 0, $line, $line_s); } else { return array('p', 0, 0, $line, $line_s); } } // Function: _wiki_reduce_line // Access: INTERNAL // Parameters: $block the tokens in the block // $line the line stack // $line_s line texts // Returns: html fragment // modified block // Description: Reduce the current line and append it to the current block. // The reduction of a single line checks for: // - non reduced :// or mailto: urls // - non reduced wiki words // - headers // - blockquote levels // - enumerated lists // - table rows // function _wiki_reduce_line ( $block, $line, $line_s ) { // wiki words list($line, $line_s) = _wiki_replace_wikiwords($line, $line_s); if (count($line) == 1 && $line[0] == '-' && (strlen($line_s[0]) == 4 || strlen($line_s[0]) == 3)) { // horiz \n----\n $html = _wiki_reduce_block($block); return array($html . "\n
    \n", array()); } if (count($line) > 2 && $line[0] == '+' && $line[1] == ' ' && strlen($line_s[0]) <= 6) { // \n+++++ headline 1..6 list($line, $line_s) = _wiki_merge($line, $line_s, 2, false, true); $html = _wiki_reduce_block($block); $level = strlen($line_s[0]); $html .= "\n".trim($line_s[2])."\n"; return array($html, array()); } return _wiki_shift_reduce_block($block, $line, $line_s); } // Function: _wiki_shift_reduce // Access: INTERNAL // Parameters: $line // $line_s // $tok // $tok_s // Returns: the new line state // Description: Shifts the given token on the stack and reduces the stack // returning a new line state. // function _wiki_shift_reduce ( $line, $line_s, $tok, $tok_s ) { switch ($tok) { case "u": // "__" $offs = _wiki_offset($line, _wiki_inline_start($tok)); if ($offs !== false) { list($line, $line_s) = _wiki_merge($line, $line_s, $offs+1, false, true); array_pop($line); $text = array_pop($line_s); array_pop($line); array_pop($line_s); $line[] = 'html'; $line_s[] = _wiki_inline_html($tok, $text); } else { $line[] = $tok; $line_s[] = $tok_s; } break; case "em": case "strong": case "sup": case '}}': // "//" or "**" or "^^" or {{ }} $offs = _wiki_offset($line, _wiki_inline_start($tok)); if ($offs !== false) { list($line, $line_s) = _wiki_merge($line, $line_s, $offs+1, false, true); array_pop($line); $text = array_pop($line_s); array_pop($line); array_pop($line_s); $line[] = 'html'; $line_s[] = _wiki_inline_html($tok, $text); } else { $line[] = $tok; $line_s[] = $tok_s; } break; case '@@': // @@---minus+++revision@@ $offs = _wiki_offset($line, '@@'); if ($offs !== false) { list($line, $line_s) = _wiki_reduce_revise($line, $line_s, $offs); } else { $line[] = $tok; $line_s[] = $tok_s; } break; case '##': // ##color|text## $offs = _wiki_offset($line, '##'); if ($offs !== false) { list($line, $line_s) = _wiki_reduce_colortext($line, $line_s, $offs); } else { $line[] = $tok; $line_s[] = $tok_s; } break; case ']': // [uri descr] $offs = _wiki_offset($line, '['); if ($offs !== false) { list($line, $line_s) = _wiki_reduce_link($line, $line_s, $offs); } else { $line[] = $tok; $line_s[] = $tok_s; } break; case ']]': // [[# anchor-name]] // [[image image-pars]] // [[image:image-pars]] $offs = _wiki_offset($line, '[['); if ($offs !== false && $line[$offs+1] == '#') { list($line, $line_s) = _wiki_reduce_anchor($line, $line_s, $offs); } else if ($offs !== false && $line[$offs+1] == 'word' && $line_s[$offs+1] == 'image') { list($line, $line_s) = _wiki_reduce_image($line, $line_s, $offs); } else #MediaWiki-style link { list($line, $line_s) = _wiki_reduce_freelink($line, $line_s, $offs); } # else # { # $line[] = $tok; # $line_s[] = $tok_s; # } break; case '))': // ((name|descr)) $offs = _wiki_offset($line, '(('); if ($offs !== false) { list($line, $line_s) = _wiki_reduce_freelink($line, $line_s, $offs); } else { $line[] = $tok; $line_s[] = $tok_s; } break; case 'comment': $line[] = 'html'; $line_s[] = ''; break; default: $line[] = $tok; $line_s[] = $tok_s; break; } return array($line, $line_s); } // helper for @@--- +++ @@ revision patterns function _wiki_reduce_revise ( $line, $line_s, $offs ) { // @@---minus+++revision@@ $len = count($line_s); $offs = _wiki_offset($line, '@@'); if ( $offs !== false && $offs < $len-1 && ($line_s[$offs+1] == '---' || $line_s[$offs+1] == '+++')) { if ($line_s[$offs+1] === '---') { $offs_del = $offs+1; $offs_ins = $offs+2; // Try to find the '+++' while ($offs_ins < $len && $line_s[$offs_ins] != '+++') { $offs_ins++; } } else { $offs_del = false; $offs_ins = $offs+1; } if ($offs_ins < $len) { list($line, $line_s) = _wiki_merge($line, $line_s, $offs_ins+1, false, true); array_pop($line); $ins = array_pop($line_s); // Remove the '+++' array_pop($line); array_pop($line_s); } else { $ins = false; } if ($offs_del !== false) { list($line, $line_s) = _wiki_merge($line, $line_s, $offs_del+1, false, true); array_pop($line); $del = array_pop($line_s); // Remove the '---' array_pop($line); array_pop($line_s); } else { $del = false; } // Remove the '@@'; array_pop($line); array_pop($line_s); if (!empty($del)) { $line[] = 'html'; $line_s[] = _wiki_inline_html('del', $del); } if (!empty($ins)) { $line[] = 'html'; $line_s[] = _wiki_inline_html('ins', $ins); } } return array($line, $line_s); } // helper for [[# anchor-name]] function _wiki_reduce_anchor ( $line, $line_s, $offs ) { // fetch the anchor name list($line, $line_s) = _wiki_merge($line, $line_s, $offs+2, -1, false, false); // pop the name array_pop($line); $name = array_pop($line_s); // pop the # array_pop($line); array_pop($line_s); $line[$offs] = 'html'; $line_s[$offs] = ''; return array($line, $line_s); } // helper for [[image path/to/image image-pars]] function _wiki_reduce_image ( $line, $line_s, $offs ) { // fetch the complete text list($line, $line_s) = _wiki_merge($line, $line_s, $offs+2, -1, false, false); // pop the image path and parameters array_pop($line); $text = trim(array_pop($line_s)); // pop 'image' array_pop($line); array_pop($line_s); //PH: "image:..." syntax if ($text[0] == ':') { $text = substr($text,1); } // Extract the interesting parts from the image description $pos = strpos($text, ' '); if ($pos === false) { $src = $text; $attr = array(); } else { $src = substr($text, 0, $pos); $attr = _wiki_get_attrs(substr($text, $pos+1)); } // Remove double quotes around the uri, some people do type them... if (strlen($src) >= 2 && $src{0} == '"' && $src{strlen($src)-1} == '"') { $src = substr($src, 1, -1); } // We have to postpone the image generation till 'showtime' because an image // typically refers to data that is dynamic. So we just pack the image data // in a special tag and do an expand in smarty. if ( ( strpos($src, '://') !== false || strpos($src, '/') !== false || preg_match('/^[a-zA-Z0-9_]+\.[a-z]{3}$/', $src)) && ( empty($attr['link']) || ( strpos($attr['link'], '://') !== false && strncasecmp($attr['link'], 'popup:', 6) != 0))) { if (!empty($attr['link'])) { // Remove double quotes around the uri, some people do type them... $link = $attr['link']; if (strlen($link) >= 2 && $link{0} == '"' && $link{strlen($link)-1} == '"') { $link = substr($link, 1, -1); } $pre = ''; $post = ''; unset($attr['link']); } else { $pre = ''; $post = ''; } $html = $pre . '$value) { $html .= htmlspecialchars($label) . '="' . htmlspecialchars($value) .'" '; } $html .= '/>' . $post; } else { // Pack the attributes so that we can easily expand them again. $html = ''; } $line[$offs] = 'html'; $line_s[$offs] = $html; return array($line, $line_s); } // helper for ##color| ## colored text function _wiki_reduce_colortext ( $line, $line_s, $offs ) { // Check for the optional description $space = _wiki_after($line, '|', $offs); if ($space != false) { // Fetch description of link list($line, $line_s) = _wiki_merge($line, $line_s, $space+1, -1, true); array_pop($line); $text = trim(array_pop($line_s)); array_pop($line); array_pop($line_s); } else { $text = false; } // Merge all tokens for the color list($line, $line_s) = _wiki_merge($line, $line_s, $offs+1, -1, false); array_pop($line); $color = trim(array_pop($line_s)); if ( (strlen($color) == 3 || strlen($color) === 6) && preg_match('/^[0-9a-fA-F]+$/', $color)) { $color = '#' . $color; } // pop the opening '##' array_pop($line); array_pop($line_s); // Create the span if (!empty($text)) { $line[] = 'html'; $line_s[] = "$text"; } return array($line, $line_s); } // helper for [uri descr] function _wiki_reduce_link ( $line, $line_s, $offs ) { // Keep a copy of line/line_s in case we don't find an uri $line0 = $line; $line_s0 = $line_s; // Check for the optional description $space = _wiki_after($line, ' ', $offs); if ($space != false) { // Fetch description of link list($line, $line_s) = _wiki_merge($line, $line_s, $space, -1, false); array_pop($line); $descr = trim(array_pop($line_s)); // Try to fetch any optional attributes list($descr, $attrs) = _wiki_split_descr_attrs($descr); } else { $descr = false; $attrs = false; } // Merge all tokens for the uri list($line, $line_s) = _wiki_merge($line, $line_s, $offs+1, -1, false, false); array_pop($line); $uri = array_pop($line_s); // only accept this construct when the uri looks like an uri $colon = strpos($uri, ':'); $dot = strpos($uri, '.'); $last = strlen($uri) - 1; if ( strpos($uri, '/') !== false || strpos($uri, '#') !== false || ($dot !== false && $dot < $last) || ($colon > 0 && $colon < $last)) { // pop the opening '[' array_pop($line); array_pop($line_s); // Create the link if (empty($descr)) { // Footnote $html = '' . _wiki_make_link($uri, '*', '', $attrs) .''; } else { // Described link $html = _wiki_make_link($uri, $descr, '', $attrs); } $line[] = 'html'; $line_s[] = $html; } else { // No uri found, do not reduce the found [uri descr] construct $line = $line0; $line_s = $line_s0; $line[] = ']'; $line_s[] = ']'; } return array($line, $line_s); } // helper for ((uri|descr)) function _wiki_reduce_freelink ( $line, $line_s, $offs ) { // Check for the optional description $anchor = false; $pipe = _wiki_after($line, '|', $offs); if ($pipe != false) { $hash = _wiki_after($line, '#', $pipe, true); if ($hash !== false) { list($line, $line_s) = _wiki_merge($line, $line_s, $hash+1, -1, false, false); array_pop($line); $anchor = '#' . trim(array_pop($line_s)); array_pop($line); array_pop($line_s); } // Fetch description of link list($line, $line_s) = _wiki_merge($line, $line_s, $pipe+1, -1, false); array_pop($line); $descr = trim(array_pop($line_s)); list($descr, $attrs) = _wiki_split_descr_attrs($descr); array_pop($line); array_pop($line_s); } else { $descr = false; $attrs = false; } // Merge all tokens for the uri (we will need unescaped text for this one) list($line, $line_s) = _wiki_merge($line, $line_s, $offs+1, -1, false, false); array_pop($line); $uri = array_pop($line_s); // pop the opening '[' array_pop($line); array_pop($line_s); // Create the link $line[] = 'html'; $line_s[] = _wiki_make_link($uri, $descr, $anchor, $attrs); return array($line, $line_s); } // Function: _wiki_offset // Access: INTERNAL // Parameters: $stack stack with tokens // $tok try to find this token // $start (optional) look below this offset // Returns: offset in stack // false when not found // Description: try to locate the token the stack in the stack, // starting to search on top // function _wiki_offset ( $stack, $tok, $start = false ) { if ($start === false) { $start = count($stack) - 1; } else { $start--; } // Don't scan through tds... while ( $start >= 0 && $stack[$start] != $tok && ($tok == '||' || $stack[$start] != '||')) { $start--; } if ($start < 0 || $stack[$start] != $tok) { $start = false; } return $start; } // Function: _wiki_after // Access: INTERNAL // Parameters: $line list of tokens // $tok token to find // $offs offset to start above // $space (optional) set to false to disallow whitespace // Returns: false when not found // offset otherwise // Description: find the given token _after_ the given offset // function _wiki_after ( $line, $tok, $offset, $space = true ) { $ct = count($line); while ( $offset < $ct && $line[$offset] != $tok && ($space || $line[$offset] != ' ')) { $offset ++; } if ($offset == $ct || $line[$offset] != $tok) { return false; } else { return $offset; } } // Function: _wiki_merge // Access: INTERNAL // Parameters: $stack the token stack // $stack_s the texts of the stack // $depth the offset to start the merge // $count number of tokens to merge (-1 for all) // $replace do some wikiword on uri replacements // $escape (optional) set to false to not escape html specialchars // Returns: modified token stack // Description: merges the given entries into one textual entry // literal and word entries will be escaped with htmlspecialchars. // function _wiki_merge ( $stack, $stack_s, $offset, $count, $replace, $escape = true ) { if ($count <= 0) { $len = count($stack); } else { $len = min(count($stack), $offset+$count); } $text = ''; for ($i=$offset; $i<$len; $i++) { if ($replace && $stack[$i] == 'wiki-word') { $text .= _wiki_make_link($stack_s[$i],''); } else if ($stack[$i] == 'html') { $text .= $stack_s[$i]; } else if ($stack[$i] == 'literal') { $text .= '' . htmlspecialchars($stack_s[$i]) . ''; } else if ($replace && $stack[$i] == 'url') { @list($protocol, $address) = explode('://', $stack_s[$i]); $text .= '' . htmlspecialchars($address) . ""; } else if ($replace && $stack[$i] == 'mailto') { // Add a marker to the mailto so that we can rebuild the wiki text $text .= '' . substr(htmlspecialchars($stack_s[$i]), 7) . ''; } else if ($escape) { $text .= htmlspecialchars($stack_s[$i]); } else { $text .= $stack_s[$i]; } } if ($len == count($stack)) { array_splice($stack, $offset); array_splice($stack_s, $offset); } else { array_splice($stack, $offset, $count); array_splice($stack_s, $offset, $count); } if ($escape) { $stack[] = 'html'; } else { $stack[] = 'text'; } $stack_s[] = $text; return array($stack, $stack_s); } // Function: _wiki_make_link // Access: INTERNAL // Parameters: $uri url, not escaped // $descr description, escaped // $anchor optional anchor ('#anchor') // $attrs attributes ( attr="value" ) // Returns: complete anchor tag // Description: creates the anchor tag for the given uri and descr. // when descr is empty then the anchor tag is generated from the uri. // function _wiki_make_link ( $uri, $descr, $anchor = '', $attrs = array() ) { $uri = trim($uri); if (!empty($descr)) { $descr = trim($descr); } // Remove double quotes around the uri, some people do type them... if (strlen($uri) >= 2 && $uri{0} == '"' && $uri{strlen($uri)-1} == '"') { $uri = substr($uri, 1, -1); } $pre = ''; $post = ''; if (!empty($attrs)) { $attrs = ' ' . implode(' ', $attrs); } else { $attrs = ''; } // 1. Check if the uri is a complete one if (strncasecmp($uri, 'mailto:', 7) == 0) { // Add a marker to the mailto so that we can rebuild the wiki text $descr = trim($descr); if (!empty($descr)) { $descr = ' '.$descr; } $text = '' . htmlspecialchars(substr($uri, 7)) . htmlspecialchars($descr) . ''; // Bail out! return $text; } else if ( strpos($uri, '/') === false && !preg_match('/^[a-zA-Z0-9_\-]+\.[a-zA-Z]{2,4}/', $uri) && strncasecmp($uri, 'javascript:', 11) != 0) { // assume symbolic name if (empty($descr)) { // Bail Out: Make special runtime tag, we will need the title of the thing we are linking to... $pre = ''; $post = ''; $descr = htmlspecialchars($uri); } if (!empty($uri)) { $uri = "id.php/" . str_replace(' ', '%20', $uri); } else if (empty($anchor)) { $anchor = '#'; } } else if ( !empty($uri) && strpos($uri, '://') === false && strncasecmp($uri, 'javascript:', 11) != 0 && preg_match('/^[a-z]+(\.[a-z]+)(\.[a-z]+)+(\/.*)?$/', $uri)) { // Make sure we have a protocol for our link, better for tags $uri = 'http://' . $uri; } // 2. Extract a description when we don't have one if (empty($descr) && strpos($uri, '://') !== false) { list($protocol, $col, $descr) = explode('://', $uri); } if (empty($descr)) { $descr = $uri; } if (isset($GLOBALS['any_acl'])) { $uri = $GLOBALS['any_acl']->filterUri($uri); } return $pre . '' . $descr . '' . $post; } // Function: _wiki_inline_start // Access: INTERNAL // Parameters: $descr // Returns: list($descr, $attrs) // Description: splits any attr="value" attributes from the given description // returns the descr and the list of attributes // function _wiki_split_descr_attrs ( $descr ) { global $_attrs; $_attrs = array(); $descr = preg_replace_callback('/\s([a-zA-Z]+)=("|")(.*?)("|")/', '_wiki_collect_attr', ' ' . $descr); return array(trim($descr), $_attrs); } // Helper function to collect all attributes from the descr function _wiki_collect_attr ( $match ) { global $_attrs; global $any_acl; if ( $match[1] == 'target' || $match[1] == 'class' || $any_acl->allowHtml()) { $_attrs[] = $match[1] . '="' . $match[3] . '"'; return ''; } else { return $match[0]; } } // Function: _wiki_inline_start // Access: INTERNAL // Parameters: $tok // Returns: start token for $tok // Description: returns the start token belonging to the inline token $tok // function _wiki_inline_start ( $tok ) { switch ($tok) { case '}}': return '{{'; default: break; } return $tok; } // Function: _wiki_inline_html // Access: INTERNAL // Parameters: $tok // $text // Returns: html for text // Description: surrounds text with the correct html tags for $tok // function _wiki_inline_html ( $tok, $text ) { switch ($tok) { case '}}': $tag = 'tt'; break; default: $tag = $tok; break; } return "<$tag>$text"; } // Function: _wiki_replace_wikiwords // Access: INTERNAL // Parameters: $line // $line_s // $offset (optional) start scanning at offset // $end (optional) stop at offset // Returns: (line, line_s) // Description: scans the line for WikiWords, when found then replaces them // with HTML fragments for freelinks. // function _wiki_replace_wikiwords( $line, $line_s, $offset = 0, $end = false ) { if ($end === false) { $end = count($line); } for ($i = $offset; $i< $end; $i++) { if ($line[$i] == 'wiki-word') { $line[$i] = 'html'; $line_s[$i] = _wiki_make_link($line_s[$i], ''); } } return array($line, $line_s); } // Function: _wiki_get_attrs // Access: INTERNAL // Parameters: $text the text containing 'attr="value"' pairs // Returns: array with attr=>value pairs // Description: parses the attributes of a tag // function _wiki_get_attrs ( $text ) { $parts = explode('="', trim($text)); $last = count($parts) - 1; $attrs = array(); $key = false; foreach ($parts as $i => $val) { if ($i == 0) { $key = trim($val); } else { $pos = strrpos($val, '"'); $attrs[$key] = stripslashes(substr($val, 0, $pos)); $key = trim(substr($val, $pos+1)); } } return $attrs; } // Function: _wiki_toc // Access: INTERNAL // Parameters: $html html with a toc marker // Returns: html with a table of contents // Description: Inserts a table of contents into the html // function _wiki_toc ( $html ) { global $toc_nr; global $toc_base; global $toc; $pos = strpos($html, ''); if ($pos !== false) { $toc_base = abs(crc32(microtime(true).'-'.rand(0,100))); $toc_nr = 0; // 1. Find all tags for insertion in the table of contents, no h1 tags are inserted $html = preg_replace_callback('|()(.*)()|U', '_wiki_toc_accum', $html); // 2. Create the table of contents at the place of the toc tag $s = "\n
      \n"; foreach ($toc as $entry) { list($anchor, $level, $title) = $entry; $s .= "
    • $title
    • \n"; } $s .= "
    \n\n"; $html = str_replace('', $s, $html); } return $html; } function _wiki_toc_accum ( $ms ) { global $toc_nr; global $toc_base; global $toc; $toc_nr++; $anchor = "$toc_base-$toc_nr"; $toc[] = array($anchor, $ms[1]{2}, $ms[2]); return $ms[1]."".$ms[2].$ms[3]; } ?> uri) when input is an array // uri when input is a single id // Description: Translates a thing id to an absolute uri. // Depending on the sharing status and the refering identity // the uri will direct to either the own or the refered // identity. // function any_thing_uri_abs ( $thg_id, $idn_id = null, $lang = null, $commit = null ) { return any_thing_uri($thg_id, $idn_id, $lang, $commit, true); } // Function: any_thing_uri // Access: EXTERNAL // Parameters: $thg_id Id of thing (may be an array) // $idn_id (optional) Identity reading the uris // $lang (optional) The target _must_ have this language // $commit (optional) not used (for now) // $abs (optional,internal) Force absolute uri // Returns: array(id => uri) when input is an array // uri when input is a single id // Description: Translates a thing id to an uri. // Depending on the sharing status and the refering identity // the uri will direct to either the own or the refered // identity. // function any_thing_uri ( $thg_id, $idn_id = null, $lang = null, $commit = null, $abs = false ) { if ($abs) { return 'http://' . $_SERVER['HTTP_HOST'] . "/id/" . urlencode($thg_id); } else { return 'id/' . urlencode($thg_id); } } // Function: any_uri_abs // Access: EXTERNAL // Parameters: $uri // Returns: uri with hostname etc. // Description: Prepends (when needed) the given uri with a full domain name. // function any_uri_abs ( $uri ) { if (strpos($uri, '://') === false) { $uri = 'http://' . $_SERVER['HTTP_HOST'] . '/' . ltrim($uri, '/'); } return $uri; } // Function: any_symbolic2id // Access: EXTERNAL // Parameters: $symbolic Symbolic name to look for // $options Options for search // Returns: id of thing with given symbolic id // false when no id found // Description: return id of thing with the given symbolic name // a thing of the internal source prevails above things // of external sources. // Optionally the selection is reduced to only the // own things and/or things of a certain kind. // When the symbolic id matches the pattern [0-9]+ then // the symbolic id is assumed to be a real id and the id // is returned as is. // function any_symbolic2id ( $symbolic, $options = array() ) { return false; } // Function: any_attach_label2pred // Access: EXTERNAL // Parameters: label label or nr of attachment // Returns: list(predicate, ord_nr) // Description: translates a label or nr to the correct predicate/ order nr. // // A label can have the format of FIG01, FIG02, ICON or DOC01 // Or just be a number, in that case we assume that the user // is refering to a figure. // The first figure is nr 1. Internally we use nr 0 for the // first figure. // function any_attach_label2pred ( $label ) { if (strcasecmp($label, 'ICON') == 0) { $pred = 'ICON'; $nr = 1; } else if (strncasecmp($label, 'FIG', 3) == 0) { $pred = 'FIGURE'; $nr = @intval(substr($label, 3)); } else if (strncasecmp($label, 'DOC', 3) == 0) { $pred = 'DOCUMENT'; $nr = @intval(substr($label, 3)); } else { // Assume numeric $pred = 'FIGURE'; $nr = @intval($label); } // We need an offset from 0 if ($nr > 0) { $nr--; } else { $nr = 0; } return array($pred, $nr); } // Function: any_attach_caption_label // Access: EXTERNAL // Parameters: thg_id thing id // pred predicate (figure, icon, document) // nr order nr of figure etc. (0..n) // Returns: list(att_id, alt, caption) // false when not found // Description: tryes to find the named attachment. // returns the found attachment id, the alt and the caption text // does not consider _any_ access rights! // // In anyMeta a 'thing' can have many images attached to it. // This images are 'things' of the kind 'attachment'. // We identify a particular image by a predicate on the edge // to the image and by the order nr. // // The alt text is typically a short title describing the image. // The caption text could be longer and is typically shown underneath // the image. // function any_attach_caption_pred ( $thg_id, $label ) { return false; } // Function: any_attach_caption // Access: EXTERNAL // Parameters: thg_id thing id // Returns: list(alt, caption) // false when not found // Description: returns the alt and the caption text of the attachment // does not consider _any_ access rights! // // an attachment is an image, mainly used in the context of // articles etc. see the function any_attach_caption_label() // above for a short discussion about attachments. // function any_attach_caption ( $thg_id ) { return false; } // Function: any_thing_title_short // Access: EXTERNAL // Parameters: $thg_id Id of the thing (may be an array, must be real id) // $usr_id (optional) User reading the titles // $lang (optional) Preferred language array // Returns: array(id=>title) // error string with error message // Description: Reads the short titles of the given thing(s). // // in anyMeta every thing must have a title. it might also have a // short title. this function returns the short title, and when // missing it returns the (long) title. // function any_thing_title_short ( $thg_id, $usr_id = null, $lang = null ) { $ts = array(); if (!is_array($thg_id)) { foreach ($thg_id as $id) { $ts[$id] = 'title of ' . htmlspecialchars($id); } } else { $ts[$thg_id] = 'title of ' . htmlspecialchars($thg_id); } return $ts; } // Function: any_text_utf8 // Access: EXTERNAL // Parameters: $html text to check // Returns: utf8 version of text // Description: This checks the input string to be really utf8, replaces non utf8 characters // with a question mark. This validity check is needed before you want to parse // the string with any XML parser. // function any_text_utf8 ( $html ) { if (function_exists('iconv')) { do { $ok = true; $text = @iconv('UTF-8', 'UTF-8//TRANSLIT', $html); if (strlen($text) != strlen($html)) { // Remove the offending character... $html = $text . '?' . substr($html, strlen($text) + 1); $ok = false; } } while (!$ok); } return $html; } // Function: any_encode_mailto // Access: EXTERNAL // Parameters: $href mailto link // $text (optional) description for link // Returns: for mailto // Description: This generates the anchor-tag for an mailto url. // The email address is encoded so that most web-bots won't recognise // it as an email address. // function any_encode_mailto ( $href, $text = '', $encode = 'javascript' ) { if (substr($href, 0, 7) == 'mailto:') { $href = substr($href, 7); } if (empty($text)) { $text = $href; } $html = '' . htmlspecialchars(str_replace('@',' [at] ',$text), ENT_QUOTES) . ''; if ($encode == 'javascript' ) { // Double encode the text using javascript // $js = ''; for ($x=0; $x < strlen($html); $x++) { if (rand(0,5) == 1) { $js .= '\'+\''; } if (strchr('><\'@', $html[$x]) !== false || rand(0,2) == 1) { $js .= '%' . bin2hex($html[$x]); } else { $js .= $html[$x]; } } $html = ''; $js = ''; for ($x=0; $x < strlen($html); $x++) { if (strchr('><\'', $html[$x]) !== false || rand(0,2) == 1) { $js .= '%' . bin2hex($html[$x]); } else { $js .= $html[$x]; } } $html = ''; } else { // Simple non-javascript version // $text_encode = ''; for ($x=0; $x < strlen($href); $x++) { $text_encode .= '&#' . ord($href[$x]) . ';'; } $href = $text_encode; $text_encode = ''; $text = str_replace('@', ' [at] ', $text); for ($x=0; $x < strlen($text); $x++) { $text_encode .= '&#' . ord($text[$x]) . ';'; } $text = $text_encode; $html = "$text"; } return $html; } // Class: Anymeta_ACL // Access: EXTERNAL // Provides: Access control for the anymeta system // class Anymeta_ACL { function Anymeta_ACL () { } // Function: Anymeta_ACL::allowHtml // Access: PUBLIC // Parameters: - // Returns: false when user is not allowed to edit html text // true when user is allowed to edit html text // Description: Checks if the current user is allowed to edit html. // This is a very special right, and should be given // with caution! // // This should be a right of an editor, letting normal users // enter HTML really defies the idea of an wiki, and of the // security of letting people enter markup text. // function allowHtml () { return defined('ALLOWHTML'); } // Function: Anymeta_ACL::filterUri // Access: PUBLIC // Parameters: uri uri to be filtered // Returns: '' when uri was not allowed // uri when uri was allowed // Description: Checks the given uri with the access permissions of the user. // The user needs text/html permissions for entering javascrpt uris. // function filterUri ( $uri ) { $allow = false; $uri = trim($uri); $u = urldecode($uri); if ( strpos($u, '&#') === false && strpos($u, '"') === false && strncasecmp($u, 'javascript:', 11) != 0) { $allow = true; } if (!$allow) { // user needs to have the right to edit HTML $allow = $this->allowHtml(); } return $allow ? $uri : ''; } } $any_acl = new Anymeta_ACL(); ?> base width in pixels for images // height base height in pixels for images // thg_id the id of the thing the texts belong to // (needed to find images) // function any_wiki_runtime ( $text, $options = array() ) { global $_wiki_options; $_wiki_options = $options; // 1. Filter remainings of and html tags $text = preg_replace('//', '', $text); // 2. Grep all image tags and produce tags. $text = preg_replace_callback('//', '_wiki_runtime_image', $text); // 3. Handle the runtime replacement of links $text = preg_replace_callback('/.+?/', '_wiki_runtime_link', $text); // 4. Handle the runtime replacement of mailto hrefs $text = preg_replace_callback('/([^ ]+?)( .+?)?/', '_wiki_runtime_mailto', $text); if (!empty($options['abs_uri'])) { // 5. Make the id.php/xxxx uris absolute $text = preg_replace_callback('||', '_wiki_runtime_anchor_abs_uri', $text); } return $text; } // Function: any_wiki_runtime_image_labels // Access: EXTERNAL // Parameters: $text the text to be expanded // Returns: array with image indices used // Description: Fetch all image nrs used in the given text. // Does recognise the 'FIGxx' format for labels. // Does also handle numerical references correctly // function any_wiki_runtime_image_labels ( $text ) { $image = array(); if (preg_match_all('//', $text, $ms, PREG_PATTERN_ORDER)) { foreach ($ms[1] as $m) { if (strncasecmp($m, 'FIG', 3) == 0) { $image[] = @intval(substr($m,3)) - 1; } else if (is_numeric($m) && $m < 100) { $image[] = intval($m) - 1; } } sort($image); } return $image; } // Function: _wiki_runtime_link // Access: INTERNAL // Parameters: $matches pattern match of the tag // Returns: tag // Description: runtime produces the tag with the correct title. // function _wiki_runtime_link ( $matches ) { global $_wiki_options; $page = $matches[1]; $abs_uri = !empty($_wiki_options['abs_uri']); $attr = ''; $ct = count($matches); for ($i=2; $i<$ct; $i+=3) { $attr .= ' ' . $matches[$i]; } @list($page, $anchor) = explode('#', $page); if (strncasecmp($page, 'uri:', 4) == 0) { $page = substr($page, 4); } else if ( strpos($page, '://') === false && strpos($page, '/' ) === false) { // try to translate the given name to an anymeta id $thg_id = any_symbolic2id($page); } if (!empty($thg_id)) { // It is an anymeta id, use the anymeta routines to generate the link $text = any_thing_title_short($thg_id); if (is_array($text)) { $text = reset($text); } if (empty($text)) { $text = $page; } // Fetch the uri, prefered from the pre-fetched uris in the template if ($abs_uri) { $href = any_thing_uri_abs($thg_id); } else { $href = any_thing_uri($thg_id); } // Add the anchor if (!empty($anchor)) { $href .= "#$anchor"; } $html = '' . htmlspecialchars($text) . ''; } else if (strpos($page, '://') !== false) { $n = strpos($page, '://'); $text = substr($page, $n+3); $html = "".htmlspecialchars($text).""; } else { // the page does not exist, show the page name and // the "new page" text $page = htmlspecialchars($page); $url = 'id.php/'.urlencode($page); if ($abs_uri) { $url = any_uri_abs($url); } $html = "$page"; } return $html; } // Function: _wiki_runtime_anchor_abs_uri // Access: INTERNAL // Parameters: $matches pattern of the tag // Returns: modified tag // Description: makes the enclose uri absolute // function _wiki_runtime_anchor_abs_uri ( $matches ) { return ''; } // Function: _wiki_runtime_mailto // Access: INTERNAL // Parameters: $matches pattern match of the tag // Returns: tag // Description: runtime produces the tag with the correct title. // function _wiki_runtime_mailto ( $matches ) { global $_wiki_options; if (empty($_wiki_options['nojavascript'])) { $encode = 'javascript'; } else { $encode = 'entities'; } return any_encode_mailto($matches[1], @trim($matches[2]), $encode); } // Function: _wiki_runtime_image // Access: INTERNAL // Parameters: $matches pattern match of the tag // Returns: tag // Description: runtime produce the tag for the given image description // function _wiki_runtime_image ( $matches ) { global $_wiki_options; $attr = array(); $src = $matches[1]; $ct = count($matches); for ($i=2; $i<$ct; $i+=3) { $attr[trim($matches[$i+1])] = $matches[$i+2]; } $base_thg_id = !empty($_wiki_options['thg_id']) ? $_wiki_options['thg_id'] : false; $base_width = !empty($_wiki_options['width']) ? $_wiki_options['width'] : 400; $base_height = !empty($_wiki_options['height']) ? $_wiki_options['height'] : 400; $abs_uri = !empty($_wiki_options['abs_uri']) ? $_wiki_options['abs_uri'] : false; // Fetch the requested width and height if (!empty($attr['width'])) { $width = _wiki_runtime_img_size($attr['width'], $base_width); } else { $width = round($base_width); } if (!empty($attr['height'])) { $height = _wiki_runtime_img_size($attr['height'], $base_height); } else { $height = round($base_height); } if (substr($src, 0, 1) == '"' && substr($src, -1) == '"') { $src = substr($src, 1, -1); } $src = trim($src); // See where we have to fetch the image from if (!empty($src)) { if (strpos($src, 'uri:') === 0) { // direct uri $src = substr($src, 4); $id = false; } else if (strpos($src, '://') === false) { if (strpos($src, ':') !== false) { list($a, $b) = explode(':', $src); if (empty($b)) { $thg_id = $a; $lbl = false; } else if (empty($a)) { $thg_id = $base_thg_id; $lbl = $b; } else { $thg_id = $a; $lbl = $b; } } else { $thg_id = $base_thg_id; $lbl = $src; } // Try to translate to a real thg_id if (!is_numeric($thg_id)) { if (empty($lbl)) { $thg_id = any_symbolic2id($thg_id, array('kind'=>'ATTACHMENT')); } else { $thg_id = any_symbolic2id($thg_id); } } // Fetch the thing id of the attachment if (!empty($lbl) && !empty($thg_id)) { list($pred, $nr) = any_attach_label2pred($lbl); @list($aid, $alt, $caption) = any_attach_caption_pred($thg_id, $pred, $nr); } else { // Assume the given src is an attachment id if (!empty($attr['caption'])) { @list($alt, $caption) = any_attach_caption($thg_id); } else { $alt = ''; $caption = ''; } $aid = $thg_id; $lbl = false; } if (empty($caption) && !empty($alt)) { $caption = $alt; } $alt = strip_tags($alt); } else { $id = false; $aid = false; $lbl = false; $alt = ''; $caption = ''; } } else { $src = '#'; // Unknown source $id = false; $aid = false; $lbl = false; } if (!empty($attr['caption'])) { if (!empty($caption)) { $alt = trim($alt); $caption = trim(str_replace(array('

    ', '

    '), array('','
    '), $caption)); while (substr($caption, -5) == '
    ') { $caption = trim(substr($caption, 0, -5)); } if (!empty($alt) && !empty($intro)) { $cap = ''; if (!empty($alt)) { $cap .= '' . any_wiki_runtime($alt, $_wiki_options) .''; } if (!empty($caption)) { $cap .= any_wiki_runtime($caption, $_wiki_options); } $cap .= ''; } else { $cap = ''; } if (strcasecmp($attr['caption'], 'before') == 0) { $cap1 = $cap; $cap2 = ''; } else { $cap1 = ''; $cap2 = $cap; } } else { $cap1 = ''; $cap2 = ''; } unset($attr['caption']); } else { $cap1 = ''; $cap2 = ''; } // // Expand the anchor tag around the image // if (array_key_exists('link',$attr)) { $link = trim($attr['link']); } else { $link = false; } $expand = false; if (empty($link) && !empty($aid)) { // Link to the attachment ;-) $href = 'id/' . $aid; if ($abs_uri) { $href = any_uri_abs($href); } } else if ($link[0] == '#') { // Ref to local anchor $href = $link; } else if ( strpos($link, '://') > 0 || strpos($link, '.php') !== false || strpos($link, '.html') !== false || strpos($link, '.htm') !== false) { // Literal link $href = $link; } else if (strncmp($link, 'javascript:', 12) == 0) { $href = $link; } else if (strncmp($link, 'popup:', 6) == 0) { $popup = substr($link, 6); if (strlen($popup) == 0) { if (is_numeric($thg_id)) { $label = addslashes($lbl); $href = "javascript:popup('$thg_id','$label')"; } else if (!empty($aid) && is_numeric($aid)) { $href = "javascript:popup('{$aid}')"; $expand = true; } } else { // Undefined behaviour for now... $href = false; } } else { // Assume a thing id if (!empty($abs_uri)) { $href = any_thing_uri_abs($link); } else { $href = any_thing_uri($link); } } // Perform any macro expansion (when needed) if (!empty($href) && $expand) { $href = str_replace(array('{$thg_id}', '{$label}', '{$att_id}'), array($thg_id, $lbl, $aid), $href); } $href = htmlspecialchars($href); // unset these so they don't show up as attributes unset($attr['link']); // Build the image tag if (!empty($aid) && is_numeric($aid)) { if (empty($attr['alt'])) { $attr['alt'] = $alt; } if (empty($attr['title'])) { $attr['title'] = $alt; } unset($attr['height']); unset($attr['width']); $pars = $attr; $pars['abs'] = $abs_uri; $img = any_attach_img_tag($aid, $pars, $width, $height); } else { if (!array_key_exists('alt', $attr)) { $attr['alt'] = basename($src); } // A normal src, build the tag ourselves $attr_s = ''; foreach ($attr as $key => $val) { $attr_s .= " $key=\"$val\""; } $img = ""; } if (!empty($href)) { $html = "$cap1
    $img$cap2"; } else { $html = "$cap1$img$cap2"; } return $html; } // Calculate a size, using a base size and a percentage // function _wiki_runtime_img_size ( $req, $base ) { if (substr($req, -2) == 'px') { // Absolute size $ret = substr($req, 0, -2); } else if (is_string($req) && is_numeric($base)) { // Assume percentage of base size if (substr($req, -1) == '%') { $req = substr($req, 0, -1); } $ret = ceil(floatval($req) * floatval($base) / 100.0); } else { // No size $ret = null; } return $ret; } ?> Animeband - FAQ