/**
 * Convert Comcode-Text to Comcode-XML.
 *
 * @param  LONG_TEXT		The comcode to convert
 * @param  boolean		Whether to not include a wrapper element (<comcode>)
 * @return LONG_TEXT		The converted comcode
 */
function comcode_text__to__comcode_xml($comcode, $skip_wrapper = false)
{
    require_code('comcode_xml');
    require_code('comcode_text');
    require_code('comcode_renderer');
    if (substr($comcode, 0, 8) == '<comcode') {
        if ($skip_wrapper) {
            return str_replace('<comcode>', '', str_replace('</comcode>', '', $comcode));
        }
        return $comcode;
    }
    $xml = '';
    global $ALLOWED_ENTITIES, $CODE_TAGS, $DANGEROUS_TAGS, $VALID_COMCODE_TAGS, $BLOCK_TAGS, $POTENTIAL_JS_NAUGHTY_ARRAY, $TEXTUAL_TAGS, $LEET_FILTER, $IMPORTED_CUSTOM_COMCODE, $REPLACE_TARGETS;
    $len = strlen($comcode);
    require_lang('comcode');
    require_code('type_validation');
    if (function_exists('set_time_limit') && ini_get('max_execution_time') != '0') {
        @set_time_limit(300);
    }
    $comcode_dangerous = true;
    $comcode_dangerous_html = true;
    // Tag level
    $current_tag = '';
    $attribute_map = array();
    $continuation = '';
    $close = mixed();
    // Properties that come from our tag
    $white_space_area = true;
    $textual_area = true;
    $formatting_allowed = true;
    $in_html = false;
    $in_semihtml = false;
    $in_separate_parse_section = false;
    // Not escaped because it has to be passed to a secondary filter
    $in_code_tag = false;
    $lax = false;
    // Our state
    $status = CCP_NO_MANS_LAND;
    $tag_stack = array();
    $pos = 0;
    $line_starting = true;
    $just_ended = false;
    $none_wrap_length = 0;
    $just_new_line = true;
    // So we can detect lists starting right away
    $just_title = false;
    global $NUM_LINES;
    $NUM_LINES = 0;
    $wrap_pos = 60;
    $preparse_mode = false;
    $is_all_semihtml = false;
    $smilies = $GLOBALS['FORUM_DRIVER']->find_emoticons();
    // We'll be needing the smiley array
    $shortcuts = array('(c)' => '&copy;', '(r)' => '&reg;', '--' => '&ndash;', '---' => '&mdash;');
    // Text syntax possibilities, that get maintained as our cursor moves through the text block
    $list_indent = 0;
    $list_type = 'ul';
    while ($pos < $len) {
        $next = $comcode[$pos];
        ++$pos;
        // State machine
        switch ($status) {
            case CCP_NO_MANS_LAND:
                if ($next == '[') {
                    // Look ahead to make sure it's a valid tag. If it's not then it's considered normal user input, not a tag at all
                    $dif = $pos < $len && $comcode[$pos] == '/' ? 1 : 0;
                    $ahead = substr($comcode, $pos + $dif, 19);
                    $equal_pos = strpos($ahead, '=');
                    $space_pos = strpos($ahead, ' ');
                    $end_pos = strpos($ahead, ']');
                    $cl_pos = strpos($ahead, chr(10));
                    if ($equal_pos === false) {
                        $equal_pos = 22;
                    }
                    if ($space_pos === false) {
                        $space_pos = 22;
                    }
                    if ($end_pos === false) {
                        $end_pos = 22;
                    }
                    if ($cl_pos === false) {
                        $cl_pos = 22;
                    }
                    $use_pos = min($equal_pos, $space_pos, $end_pos, $cl_pos);
                    $potential_tag = strtolower(substr($ahead, 0, $use_pos));
                    if ($use_pos != 22 && (!$in_html || $potential_tag == 'html' || $potential_tag == 'semihtml') && (!$in_code_tag || isset($CODE_TAGS[$potential_tag]))) {
                        if (!isset($VALID_COMCODE_TAGS[$potential_tag])) {
                            if (!$IMPORTED_CUSTOM_COMCODE) {
                                _custom_comcode_import($GLOBALS['SITE_DB']);
                            }
                        }
                        if (isset($VALID_COMCODE_TAGS[$potential_tag]) && substr($ahead, 0, 2) != 'i ') {
                            $close = false;
                            $current_tag = '';
                            $xml .= $continuation;
                            $continuation = '';
                            if ($potential_tag == 'html' || $potential_tag == 'semihtml') {
                                list($close_list, $list_indent) = _convert_close_open_lists($list_indent);
                                $xml .= $close_list;
                            }
                            $status = CCP_STARTING_TAG;
                            continue;
                        }
                    }
                }
                if ($in_html || $in_semihtml && ($next == '<' || $next == '>')) {
                    $ahead = substr($comcode, $pos - 1, 20);
                    $ahead_lower = strtolower($ahead);
                    if ($next == chr(10)) {
                        ++$NUM_LINES;
                    }
                    $continuation .= $next;
                } else {
                    // Text-format possibilities
                    if ($just_new_line && $formatting_allowed) {
                        $xml .= $continuation;
                        $continuation = '';
                        // List
                        $found_list = false;
                        $old_list_indent = $list_indent;
                        if ($pos + 1 < $len && is_numeric($next) && $comcode[$pos] == ')' && $comcode[$pos + 1] == ' ') {
                            if ($list_indent != 0 && $list_type == 'ul') {
                                list($temp_tpl, $old_list_indent) = _close_open_lists($list_indent, $list_type);
                                $xml .= $temp_tpl;
                            }
                            $list_indent = 1;
                            $found_list = true;
                            $scan_pos = $pos;
                            $list_type = '1';
                        } elseif ($pos + 1 < $len && ord($next) >= ord('a') && ord($next) <= ord('z') && $comcode[$pos] == ')' && $comcode[$pos + 1] == ' ') {
                            if ($list_indent != 0 && $list_type == 'ul') {
                                list($temp_tpl, $old_list_indent) = _close_open_lists($list_indent, $list_type);
                                $xml .= $temp_tpl;
                            }
                            $list_indent = 1;
                            $found_list = true;
                            $scan_pos = $pos;
                            $list_type = 'a';
                        } elseif ($next == ' ') {
                            if ($old_list_indent != 0 && $list_type != 'ul') {
                                list($temp_tpl, $old_list_indent) = _close_open_lists($list_indent, $list_type);
                                $xml .= $temp_tpl;
                            }
                            $scan_pos = $pos - 1;
                            $list_indent = 0;
                            while ($scan_pos < $len) {
                                $scan_next = $comcode[$scan_pos];
                                if ($scan_next == '-' && $comcode[$scan_pos + 1] == ' ') {
                                    $found_list = true;
                                    break;
                                } else {
                                    if ($scan_next == ' ') {
                                        ++$list_indent;
                                    } else {
                                        break;
                                    }
                                }
                                ++$scan_pos;
                            }
                            if (!$found_list) {
                                $list_indent = 0;
                            }
                        } else {
                            list($close_list, $list_indent) = _convert_close_open_lists($list_indent);
                            $xml .= $close_list;
                            if ($next == '-' && !$just_title) {
                                $scan_pos = $pos;
                                $found_rule = true;
                                while ($scan_pos < $len) {
                                    $scan_next = $comcode[$scan_pos];
                                    if ($scan_next != '-') {
                                        if ($scan_next == chr(10)) {
                                            ++$NUM_LINES;
                                            break;
                                        } else {
                                            $found_rule = false;
                                        }
                                    }
                                    ++$scan_pos;
                                }
                                if ($found_rule) {
                                    $xml .= '<rule />';
                                    $pos = $scan_pos + 1;
                                    $just_ended = true;
                                    $none_wrap_length = 0;
                                    continue;
                                }
                            }
                        }
                        // List handling
                        if ($list_indent == $old_list_indent && $old_list_indent != 0) {
                            $xml .= '</listElement>';
                        }
                        for ($i = $list_indent; $i < $old_list_indent; ++$i) {
                            $xml .= '</listElement>';
                            $xml .= '</list>';
                        }
                        if ($list_indent < $old_list_indent && $list_indent != 0) {
                            $xml .= '</listElement>';
                        }
                        if ($found_list) {
                            if ($list_indent - $old_list_indent > 1 && !$lax) {
                                $error = comcode_parse_error($preparse_mode, array('CCP_LIST_JUMPYNESS'), $pos, $comcode);
                                return $error->evaluate();
                            }
                            for ($i = $old_list_indent; $i < $list_indent; ++$i) {
                                switch ($list_type) {
                                    case 'ul':
                                        $xml .= '<list>';
                                        break;
                                    case '1':
                                        $xml .= '<list type="1">';
                                        break;
                                    case 'a':
                                        $xml .= '<list type="a">';
                                        break;
                                }
                                if ($i < $list_indent - 1) {
                                    $xml .= '<listElement>';
                                }
                            }
                            $xml .= '<listElement>';
                            $just_ended = true;
                            $none_wrap_length = 0;
                            $next = '';
                            $pos = $scan_pos + 2;
                        }
                    }
                    if ($next == chr(10) && $white_space_area && !$just_ended) {
                        ++$NUM_LINES;
                        $line_starting = true;
                        $xml .= $continuation;
                        $continuation = '';
                        $just_new_line = true;
                        $none_wrap_length = 0;
                        if ($list_indent == 0) {
                            $xml .= '<br />' . chr(10);
                        }
                    } else {
                        $just_new_line = false;
                        if ($next == ' ' && $white_space_area) {
                            if ($line_starting || $pos != 0 && $comcode[$pos - 2] == ' ') {
                                $next = '&nbsp;';
                                ++$none_wrap_length;
                            } else {
                                $none_wrap_length = 0;
                            }
                            $continuation .= $next;
                        } elseif ($next == "\t" && $white_space_area) {
                            $xml .= $continuation;
                            $continuation = '';
                            $tab_tpl = do_template('COMCODE_TEXTCODE_TAB');
                            // &nbsp;&nbsp;&nbsp;&nbsp;
                            $_tab_tpl = $tab_tpl->evaluate();
                            $none_wrap_length += strlen($_tab_tpl);
                            $xml .= $tab_tpl->evaluate();
                        } else {
                            if ($next == ' ' || $next == "\t" || $just_ended) {
                                $none_wrap_length = 0;
                            } else {
                                if (!is_null($wrap_pos) && $none_wrap_length >= $wrap_pos && $textual_area && !$in_semihtml) {
                                    $xml .= $continuation;
                                    $continuation = '';
                                    $xml .= '<br />' . chr(10);
                                    $none_wrap_length = 0;
                                } elseif ($textual_area) {
                                    ++$none_wrap_length;
                                }
                            }
                            $line_starting = false;
                            $just_ended = false;
                            $differented = false;
                            // If somehow via lookahead we've changed this to HTML and thus won't use it in raw form
                            // Symbol lookahead
                            if (!$in_code_tag) {
                                if ($next == '{' && ($comcode[$pos] == '$' || $comcode[$pos] == '+' || $comcode[$pos] == '!') && $comcode_dangerous) {
                                    $xml .= $continuation;
                                    $continuation = '';
                                    if ($comcode[$pos] == '+') {
                                        $p_end = $pos + 5;
                                        while ($p_end < $len) {
                                            $p_portion = substr($comcode, $pos - 1, $p_end - ($pos - 1) + 5);
                                            if (substr_count($p_portion, '{+START') == substr_count($p_portion, '{+END')) {
                                                break;
                                            }
                                            $p_end++;
                                        }
                                        $p_len = 1;
                                        while ($pos + $p_len < $len) {
                                            $p_portion = substr($comcode, $pos - 1, $p_len);
                                            if (substr_count($p_portion, '{') == substr_count($p_portion, '}')) {
                                                break;
                                            }
                                            $p_len++;
                                        }
                                        $p_len--;
                                        $p_portion = substr($comcode, $pos + $p_len, $p_end - ($pos + $p_len));
                                        $_ret = template_to_tempcode_static(substr($comcode, $pos - 1, $p_len + 1) . '!' . substr($comcode, $p_end, 6));
                                        $ret = '<directive type="' . escape_html($_ret->bits[0][2]) . '">';
                                        foreach ($_ret->bits[0][3] as $val) {
                                            $ret .= '<directiveParam>' . escape_html($val->evaluate()) . '</directiveParam>';
                                        }
                                        $ret .= comcode_text__to__comcode_xml($p_portion, true);
                                        $ret .= '</directive>';
                                        $pos = $p_end + 6;
                                    } else {
                                        $_ret = new ocp_tempcode();
                                        $_ret->bits = array(read_single_uncompiled_variable($comcode, $pos, $len));
                                        if ($_ret->bits[0][1] == TC_SYMBOL) {
                                            $ret = '<symbol>';
                                            if (isset($_ret->bits[0][3])) {
                                                foreach ($_ret->bits[0][3] as $val) {
                                                    $ret .= '<symbolParam>' . escape_html($val) . '</symbolParam>';
                                                }
                                            }
                                            $ret .= $_ret->bits[0][2] . '</symbol>';
                                        } else {
                                            $ret = '<language>';
                                            if (isset($_ret->bits[0][3])) {
                                                foreach ($_ret->bits[0][3] as $val) {
                                                    $ret .= '<languageParam>' . escape_html($val) . '</languageParam>';
                                                }
                                            }
                                            $ret .= $_ret->bits[0][2] . '</language>';
                                        }
                                    }
                                    $differented = true;
                                    $xml .= $ret;
                                }
                            }
                            // Escaping of comcode tag starts lookahead
                            if ($next == '\\' && !$in_code_tag) {
                                if ($pos != $len && $comcode[$pos] == '"') {
                                    $continuation .= '"';
                                    ++$pos;
                                    $differented = true;
                                } elseif ($pos != $len && $comcode[$pos] == '[') {
                                    $continuation .= '[';
                                    ++$pos;
                                    $differented = true;
                                } elseif ($pos != $len && $comcode[$pos] == '{') {
                                    $continuation .= '{';
                                    ++$pos;
                                    $differented = true;
                                } elseif ($pos == $len || $comcode[$pos] == '\\') {
                                    $continuation .= '\\';
                                    ++$pos;
                                    $differented = true;
                                }
                            }
                            // Smiley lookahead
                            if (!$differented) {
                                if (($textual_area || $in_semihtml) && trim($next) != '') {
                                    foreach ($smilies as $smiley => $imgcode) {
                                        if ($in_semihtml) {
                                            $smiley = ' ' . $smiley . ' ';
                                        }
                                        if ($next == $smiley[0]) {
                                            if (substr($comcode, $pos - 1, strlen($smiley)) == $smiley) {
                                                $xml .= $continuation;
                                                $continuation = '';
                                                $pos += strlen($smiley) - 1;
                                                $differented = true;
                                                $xml .= '<emoticon>' . escape_html($imgcode) . '</emoticon>';
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            if ($textual_area && trim($next) != '' && !$differented && addon_installed('cedi')) {
                                // CEDI pages
                                if ($pos < $len && $next == '[') {
                                    $matches = array();
                                    if (preg_match('#^\\[([^\\[\\]]*)\\]\\]#', substr($comcode, $pos, 40), $matches) != 0) {
                                        $cedi_page_name = $matches[1];
                                        $xml .= $continuation;
                                        $continuation = '';
                                        $hash_pos = strpos($cedi_page_name, '#');
                                        if ($hash_pos !== false) {
                                            $jump_to = substr($cedi_page_name, $hash_pos + 1);
                                            $cedi_page_name = substr($cedi_page_name, 0, $hash_pos);
                                            $xml .= '<cedi anchor="' . escape_html($jump_to) . '">' . escape_html($cedi_page_name) . '</cedi>';
                                        } else {
                                            $xml .= '<cedi>' . escape_html($cedi_page_name) . '</cedi>';
                                        }
                                        $pos += strlen($matches[1]) + 3;
                                        $differented = true;
                                    }
                                }
                                // Usernames
                                if ($pos < $len && $next == '{') {
                                    $matches = array();
                                    if (preg_match('#^\\{([^"{}&\'\\$<>]*)\\}\\}#', substr($comcode, $pos, 40), $matches) != 0) {
                                        $xml .= $continuation;
                                        $continuation = '';
                                        $username = $matches[1];
                                        if ($username[0] == '?') {
                                            $username = substr($username, 1);
                                            $xml .= '<member boxed="1">' . escape_html($username) . '</member>';
                                        } else {
                                            $xml .= '<member>' . escape_html($username) . '</member>';
                                        }
                                        $pos += strlen($matches[1]) + 3;
                                        $differented = true;
                                    }
                                }
                                if (!$in_code_tag && trim($next) != '' && !$differented) {
                                    // Shortcut lookahead
                                    if (!$differented) {
                                        foreach ($shortcuts as $code => $replacement) {
                                            if ($next == $code[0] && substr($comcode, $pos - 1, strlen($code)) == $code) {
                                                $xml .= $continuation;
                                                $continuation = '';
                                                $pos += strlen($code) - 1;
                                                $differented = true;
                                                $xml .= $replacement;
                                                break;
                                            }
                                        }
                                    }
                                }
                                // Table syntax
                                if (!$differented) {
                                    if ($pos < $len && $comcode[$pos] == '|') {
                                        $end_tbl = strpos($comcode, chr(10) . '|}', $pos);
                                        if ($end_tbl !== false) {
                                            $end_fst_line_pos = strpos($comcode, chr(10), $pos);
                                            $caption = substr($comcode, $pos + 2, max($end_fst_line_pos - $pos - 2, 0));
                                            $pos += strlen($caption) + 1;
                                            $rows = preg_split('#(\\|-|\\|\\})#Um', substr($comcode, $pos, $end_tbl - $pos));
                                            if (count($rows) == 1 && $caption == 'floats') {
                                                $cells = preg_split('/(\\n\\! | \\!\\! |\\n\\| | \\|\\| )/', $rows[0], -1, PREG_SPLIT_DELIM_CAPTURE);
                                                array_shift($cells);
                                                // First one is non-existant empty
                                                $spec = true;
                                                // Find which to float
                                                $to_float = NULL;
                                                foreach ($cells as $i => $cell) {
                                                    if (!$spec) {
                                                        if (strpos($cell, '!') !== false || is_null($to_float)) {
                                                            $to_float = $i;
                                                        }
                                                    }
                                                    $spec = !$spec;
                                                }
                                                $xml .= '<float>';
                                                // Do floated one
                                                $xml .= '<fh>';
                                                $xml .= comcode_text__to__comcode_xml(rtrim($cells[$to_float]), true);
                                                $xml .= '</fh>';
                                                // Do non-floated ones
                                                foreach ($cells as $i => $cell) {
                                                    if ($i % 2 == 1 && $i != $to_float) {
                                                        $xml .= '<fd>';
                                                        $xml .= comcode_text__to__comcode_xml(rtrim($cells[$to_float]), true);
                                                        $xml .= '</fd>';
                                                    }
                                                }
                                                $xml .= '</float>';
                                            } else {
                                                $xml .= '<table summary="' . escape_html($caption) . '">';
                                                foreach ($rows as $table_row) {
                                                    $xml .= '<tr>';
                                                    $cells = preg_split('/(\\n\\! | \\!\\! |\\n\\| | \\|\\| )/', $table_row, -1, PREG_SPLIT_DELIM_CAPTURE);
                                                    array_shift($cells);
                                                    // First one is non-existant empty
                                                    $spec = true;
                                                    $c_type = '';
                                                    foreach ($cells as $cell) {
                                                        if ($spec) {
                                                            $c_type = strpos($cell, '!') !== false ? 'th' : 'td';
                                                        } else {
                                                            $xml .= '<' . $c_type . '>';
                                                            $xml .= comcode_text__to__comcode_xml(rtrim($cell), true);
                                                            $xml .= '</' . $c_type . '>';
                                                        }
                                                        $spec = !$spec;
                                                    }
                                                    $xml .= '</tr>';
                                                }
                                                $xml .= '</table>';
                                            }
                                            $pos = $end_tbl + 3;
                                            $differented = true;
                                        }
                                    }
                                }
                                // Link lookahead
                                if (!$differented) {
                                    if (!$in_semihtml && $next == 'h' && (substr($comcode, $pos - 1, strlen('http://')) == 'http://' || substr($comcode, $pos - 1, strlen('https://')) == 'https://' || substr($comcode, $pos - 1, strlen('ftp://')) == 'ftp://')) {
                                        list($link_end_pos, $auto_link) = detect_link($comcode, $pos);
                                        $xml .= $continuation;
                                        $continuation = '';
                                        $downloaded_at_link = http_download_file($auto_link, 3000, false);
                                        $link_captions_title = '';
                                        if (is_string($downloaded_at_link)) {
                                            $matches = array();
                                            if (preg_match('#<title>\\s*(.*)\\s*</title>#', $downloaded_at_link, $matches) != 0) {
                                                require_code('character_sets');
                                                $link_captions_title = @html_entity_decode(convert_to_internal_encoding($matches[1]), ENT_QUOTES, get_charset());
                                            }
                                        }
                                        $xml .= '<url param="' . escape_html($auto_link) . '">' . escape_html($link_captions_title) . '</url>';
                                        $pos += $link_end_pos - $pos;
                                        $differented = true;
                                        break;
                                    }
                                }
                            }
                            if (!$differented) {
                                if (!$in_separate_parse_section && (!$in_semihtml || !$comcode_dangerous && !$is_all_semihtml)) {
                                    if ($next == '&') {
                                        $ahead = substr($comcode, $pos, 20);
                                        $ahead_lower = strtolower($ahead);
                                        $matches = array();
                                        $entity = preg_match('#(\\#)?([\\w]*);#', $ahead_lower, $matches) != 0;
                                        // If it is a SAFE entity, use it
                                        if ($entity) {
                                            if ($matches[1] == '' && isset($ALLOWED_ENTITIES[$matches[2]])) {
                                                $pos += strlen($matches[2]) + 1;
                                                $continuation .= '&' . $matches[2] . ';';
                                            } elseif (is_numeric($matches[2]) && $matches[1] == '#') {
                                                $matched_entity = intval(base_convert($matches[1], 16, 10));
                                                if ($matched_entity < 127 && array_key_exists(chr($matched_entity), $POTENTIAL_JS_NAUGHTY_ARRAY)) {
                                                    $continuation .= escape_html($next);
                                                } else {
                                                    $pos += strlen($matches[2]) + 2;
                                                    $continuation .= '&#' . $matches[2] . ';';
                                                }
                                            } else {
                                                $continuation .= '&amp;';
                                            }
                                        } else {
                                            $continuation .= '&amp;';
                                        }
                                    } else {
                                        $continuation .= escape_html($next);
                                    }
                                } else {
                                    $continuation .= $next;
                                }
                            }
                        }
                    }
                }
                break;
            case CCP_IN_TAG_NAME:
                if ($next == '=') {
                    $status = CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT;
                    $current_attribute_name = 'param';
                } elseif (trim($next) == '') {
                    $status = CCP_IN_TAG_BETWEEN_ATTRIBUTES;
                } elseif ($next == '[') {
                    warn_exit(do_lang_tempcode('CCP_TAG_OPEN_ANOMALY'));
                } elseif ($next == ']') {
                    if ($close) {
                        if ($formatting_allowed) {
                            list($close_list, $list_indent) = _convert_close_open_lists($list_indent);
                            $xml .= $close_list;
                        }
                        if (count($tag_stack) == 0) {
                            warn_exit(do_lang_tempcode('CCP_NO_CLOSE', escape_html($current_tag)));
                        }
                        $_last = array_pop($tag_stack);
                        if ($_last[0] != $current_tag) {
                            warn_exit(do_lang_tempcode('CCP_NO_CLOSE_MATCH', escape_html($current_tag), escape_html($_last)));
                        }
                        // Do the comcode for this tag
                        if ($in_semihtml) {
                            foreach ($_last[1] as $index => $conv) {
                                $_last[1][$index] = @html_entity_decode(str_replace('<br />', chr(10), $conv), ENT_QUOTES, get_charset());
                            }
                        }
                        $attributes = $_last[1];
                        if ($current_tag == 'html') {
                            $in_html = false;
                            $_last[0] = 'htmlWrap';
                        } elseif ($current_tag == 'semihtml') {
                            $in_semihtml = false;
                            $_last[0] = 'htmlWrap';
                        } elseif ($current_tag == 'external_table' || $current_tag == 'internal_table') {
                            $_last[0] = 'box';
                        } elseif ($current_tag == 'php') {
                            $_last[0] = 'code';
                            $attributes['param'] = 'php';
                        } elseif ($current_tag == 'codebox') {
                            $_last[0] = 'code';
                            $attributes['scroll'] = '1';
                        } elseif ($current_tag == 'sql') {
                            $_last[0] = 'code';
                            $attributes['param'] = 'sql';
                        } elseif ($current_tag == 'snapback') {
                            $_last[0] = 'post';
                        } elseif ($current_tag == 'thread') {
                            $_last[0] = 'topic';
                        } elseif ($current_tag == 'list') {
                            $sub_elements = explode('[*]', str_replace('[/*]', '', $xml));
                            $xml = '';
                            foreach ($sub_elements as $sub_element) {
                                $xml .= '<listElement>' . $sub_element . '</listElement>';
                            }
                        }
                        if ($_last[0] == 'box' && isset($attributes['breadth']) && !isset($attributes['dimensions'])) {
                            $attributes['dimensions'] = $attributes['breadth'];
                            unset($attributes['breadth']);
                        }
                        if ($_last[0] == 'page' && array_keys($attributes) != array('param')) {
                            $zone = isset($attributes['param']) ? $attributes['param'] : '_SEARCH';
                            $page = $xml;
                            $xml = $attributes['caption'];
                            unset($attributes['param']);
                            unset($attributes['caption']);
                            $pagelink = $zone . ':' . $page;
                            foreach ($attributes as $key => $val) {
                                $pagelink .= ':' . $key . '=' . $val;
                            }
                            $attributes = array('pageLink' => $pagelink);
                        }
                        if ($_last[0] == 'block') {
                            foreach ($attributes as $key => $val) {
                                $xml .= '<blockParam key="' . escape_html($key) . '" value="' . escape_html($val) . '" />';
                            }
                            $attributes = array();
                        }
                        if ($_last[0] == 'random') {
                            foreach ($attributes as $key => $val) {
                                $xml .= '<randomTarget pickIfAbove="' . escape_html($key) . '">' . comcode_text__to__comcode_xml($val, true) . '</randomTarget>';
                            }
                            $attributes = array();
                        }
                        if ($_last[0] == 'jumping') {
                            foreach ($attributes as $key => $val) {
                                $xml .= '<jumpingTarget>' . comcode_text__to__comcode_xml($val, true) . '</jumpingTarget>';
                            }
                            $attributes = array();
                        }
                        if ($_last[0] == 'concepts') {
                            foreach ($attributes as $_key => $_value) {
                                if (substr($_key, -4) == '_key') {
                                    $key = $_value;
                                    $cid = substr($_key, 0, strlen($_key) - 4);
                                    $value = $attributes[$cid . '_value'];
                                    $xml .= '<showConcept key="' . escape_html($key) . '" value="' . escape_html($value) . '" />';
                                }
                            }
                            $attributes = array();
                        }
                        if (($_last[0] == 'attachment' || $_last[0] == 'attachment_safe') && isset($attributes['description'])) {
                            $xml .= '<attachmentDescription>' . comcode_text__to__comcode_xml($attributes['description'], true) . '</attachmentDescription>';
                            unset($attributes['description']);
                        }
                        if ($_last[0] == 'hide' && isset($attributes['param'])) {
                            $xml .= '<hideTitle>' . comcode_text__to__comcode_xml($attributes['param'], true) . '</hideTitle>';
                            unset($attributes['param']);
                        }
                        if ($_last[0] == 'tooltip' && isset($attributes['param'])) {
                            $xml .= '<tooltipMessage>' . comcode_text__to__comcode_xml($attributes['param'], true) . '</tooltipMessage>';
                            unset($attributes['param']);
                        }
                        global $COMCODE_XML_PARAM_RENAMING, $COMCODE_XML_SWITCH_AROUND;
                        if (isset($attributes['param']) && isset($COMCODE_XML_PARAM_RENAMING[$_last[0]])) {
                            $attributes[$COMCODE_XML_PARAM_RENAMING[$_last[0]]] = $attributes['param'];
                            unset($attributes['param']);
                        }
                        $comcode_xml_switch_around = $COMCODE_XML_SWITCH_AROUND;
                        if ($_last[0] == 'email' && (!isset($attributes['param']) || !is_valid_email_address($attributes['param'])) && is_valid_email_address($xml)) {
                            $comcode_xml_switch_around[] = 'email';
                        }
                        if ($_last[0] == 'url' && (!isset($attributes['param']) || !looks_like_url($attributes['param'])) && looks_like_url($xml)) {
                            $comcode_xml_switch_around[] = 'url';
                        }
                        if (in_array($_last[0], $comcode_xml_switch_around)) {
                            $x = 'param';
                            if ($_last[0] == 'reference') {
                                $x = 'title';
                            }
                            if (isset($attributes[$x])) {
                                $temp = $attributes[$x];
                                $attributes[$x] = $xml;
                                $xml = comcode_text__to__comcode_xml($temp, true);
                            } else {
                                $attributes[$x] = $xml;
                            }
                        }
                        $in_code_tag = false;
                        $white_space_area = $_last[3];
                        $in_separate_parse_section = $_last[4];
                        $formatting_allowed = $_last[5];
                        $textual_area = $_last[6];
                        if ($_last[0] == 'htmlWrap') {
                            $embed_output = '<htmlWrap xmlns="http://www.w3.org/1999/xhtml">';
                        } else {
                            $embed_output = '<' . to_camelCase($_last[0]);
                            foreach ($attributes as $key => $val) {
                                $embed_output .= ' ' . to_camelCase($key) . '="' . escape_html($val) . '"';
                            }
                            $embed_output .= '>';
                        }
                        $embed_output .= $xml . '</' . to_camelCase($_last[0]) . '>';
                        $just_ended = isset($BLOCK_TAGS[$current_tag]);
                        $xml = $_last[2] . $embed_output;
                        if ($current_tag == 'title') {
                            if (strlen($comcode) > $pos + 1 && $comcode[$pos] == chr(10) && $comcode[$pos + 1] == chr(10)) {
                                $NUM_LINES += 2;
                                $pos += 2;
                                $just_new_line = true;
                                list($close_list, $list_indent) = _convert_close_open_lists($list_indent);
                                $xml .= $close_list;
                            }
                        }
                        $status = CCP_NO_MANS_LAND;
                    } else {
                        array_push($tag_stack, array($current_tag, $attribute_map, $xml, $white_space_area, $in_separate_parse_section, $formatting_allowed, $textual_area));
                        list(, , , $white_space_area, $formatting_allowed, $in_separate_parse_section, $textual_area, $attribute_map, $status, $in_html, $in_semihtml, $pos, $in_code_tag) = _opened_tag(false, false, get_member(), $attribute_map, $current_tag, $pos, $comcode_dangerous, $comcode_dangerous_html, $in_separate_parse_section, $in_html, $in_semihtml, $close, $len, $comcode);
                        $xml = '';
                    }
                } else {
                    $current_tag .= strtolower($next);
                }
                break;
            case CCP_STARTING_TAG:
                if ($next == '[') {
                    warn_exit(do_lang_tempcode('CCP_TAG_OPEN_ANOMALY'));
                } elseif ($next == ']') {
                    warn_exit(do_lang_tempcode('CCP_TAG_CLOSE_ANOMALY'));
                } elseif ($next == '/') {
                    $close = true;
                } else {
                    $current_tag .= strtolower($next);
                    $status = CCP_IN_TAG_NAME;
                }
                break;
            case CCP_IN_TAG_BETWEEN_ATTRIBUTES:
                if ($next == ']') {
                    array_push($tag_stack, array($current_tag, $attribute_map, $xml, $white_space_area, $in_separate_parse_section, $formatting_allowed, $textual_area));
                    list(, , , $white_space_area, $formatting_allowed, $in_separate_parse_section, $textual_area, $attribute_map, $status, $in_html, $in_semihtml, $pos, $in_code_tag) = _opened_tag(false, false, get_member(), $attribute_map, $current_tag, $pos, $comcode_dangerous, $comcode_dangerous_html, $in_separate_parse_section, $in_html, $in_semihtml, $close, $len, $comcode);
                    $xml = '';
                } elseif ($next == '[') {
                    warn_exit(do_lang_tempcode('CCP_TAG_OPEN_ANOMALY'));
                } elseif (trim($next) != '') {
                    $status = CCP_IN_TAG_ATTRIBUTE_NAME;
                    $current_attribute_name = $next;
                }
                break;
            case CCP_IN_TAG_ATTRIBUTE_NAME:
                if ($next == '[') {
                    warn_exit(do_lang_tempcode('CCP_TAG_OPEN_ANOMALY'));
                } elseif ($next == ']') {
                    $at_map_keys = array_keys($attribute_map);
                    $old_attribute_name = $at_map_keys[count($at_map_keys) - 1];
                    $attribute_map[$old_attribute_name] .= ' ' . $current_attribute_name;
                    array_push($tag_stack, array($current_tag, $attribute_map, $xml, $white_space_area, $in_separate_parse_section, $formatting_allowed, $textual_area));
                    list(, , , $white_space_area, $formatting_allowed, $in_separate_parse_section, $textual_area, $attribute_map, $status, $in_html, $in_semihtml, $pos, $in_code_tag) = _opened_tag(false, false, get_member(), $attribute_map, $current_tag, $pos, $comcode_dangerous, $comcode_dangerous_html, $in_separate_parse_section, $in_html, $in_semihtml, $close, $len, $comcode);
                    $xml = '';
                } elseif ($next == '=') {
                    $status = CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT;
                } elseif ($next != ' ') {
                    $current_attribute_name .= strtolower($next);
                } else {
                    $status = CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_LEFT;
                }
                break;
            case CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_LEFT:
                if ($next == '=') {
                    $status = CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT;
                } elseif (trim($next) != '') {
                    warn_exit(do_lang_tempcode('CCP_ATTRIBUTE_ERROR', escape_html($current_attribute_name), escape_html($current_tag)));
                }
                break;
            case CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT:
                if ($next == '[') {
                    warn_exit(do_lang_tempcode('CCP_TAG_OPEN_ANOMALY'));
                } elseif ($next == ']') {
                    warn_exit(do_lang_tempcode('CCP_TAG_CLOSE_ANOMALY'));
                } elseif ($next == '"' || $in_semihtml && substr($comcode, $pos - 1, 6) == '&quot;') {
                    if ($next != '"') {
                        $pos += 5;
                    }
                    $status = CCP_IN_TAG_ATTRIBUTE_VALUE;
                    $current_attribute_value = '';
                } elseif ($next != '') {
                    $status = CCP_IN_TAG_ATTRIBUTE_VALUE_NO_QUOTE;
                    $current_attribute_value = $next;
                }
                break;
            case CCP_IN_TAG_ATTRIBUTE_VALUE_NO_QUOTE:
                if ($next == ' ') {
                    $status = CCP_IN_TAG_BETWEEN_ATTRIBUTES;
                    if (isset($attribute_map[$current_attribute_name])) {
                        warn_exit(do_lang_tempcode('CCP_DUPLICATE_ATTRIBUTES', escape_html($current_attribute_name), escape_html($current_tag)));
                    }
                    $attribute_map[$current_attribute_name] = $current_attribute_value;
                } elseif ($next == ']') {
                    if (isset($attribute_map[$current_attribute_name])) {
                        warn_exit(do_lang_tempcode('CCP_DUPLICATE_ATTRIBUTES', escape_html($current_attribute_name), escape_html($current_tag)));
                    }
                    $attribute_map[$current_attribute_name] = $current_attribute_value;
                    array_push($tag_stack, array($current_tag, $attribute_map, $xml, $white_space_area, $in_separate_parse_section, $formatting_allowed, $textual_area));
                    list(, , , $white_space_area, $formatting_allowed, $in_separate_parse_section, $textual_area, $attribute_map, $status, $in_html, $in_semihtml, $pos, $in_code_tag) = _opened_tag(false, false, get_member(), $attribute_map, $current_tag, $pos, $comcode_dangerous, $comcode_dangerous_html, $in_separate_parse_section, $in_html, $in_semihtml, $close, $len, $comcode);
                    $xml = '';
                } else {
                    $current_attribute_value .= $next;
                }
                break;
            case CCP_IN_TAG_ATTRIBUTE_VALUE:
                if ($next == '"' || $in_semihtml && substr($comcode, $pos - 1, 6) == '&quot;') {
                    if ($next != '"') {
                        $pos += 5;
                    }
                    $status = CCP_IN_TAG_BETWEEN_ATTRIBUTES;
                    if (isset($attribute_map[$current_attribute_name])) {
                        warn_exit(do_lang_tempcode('CCP_DUPLICATE_ATTRIBUTES', escape_html($current_attribute_name), escape_html($current_tag)));
                    }
                    $attribute_map[$current_attribute_name] = $current_attribute_value;
                } else {
                    if ($next == '\\') {
                        if ($comcode[$pos] == '"') {
                            $current_attribute_value .= '"';
                            ++$pos;
                        } elseif ($comcode[$pos] == '\\') {
                            $current_attribute_value .= '\\';
                            ++$pos;
                        } else {
                            $current_attribute_value .= $next;
                        }
                    } else {
                        $current_attribute_value .= $next;
                    }
                }
                break;
        }
    }
    $xml .= $continuation;
    $continuation = '';
    list($close_list, $list_indent) = _convert_close_open_lists($list_indent);
    $xml .= $close_list;
    if ($status != CCP_NO_MANS_LAND || count($tag_stack) != 0) {
        $stack_top = array_pop($tag_stack);
        warn_exit(do_lang_tempcode('CCP_BROKEN_END', escape_html($stack_top[0])));
    }
    if (!$skip_wrapper) {
        $xml = '<comcode>' . $xml . '</comcode>';
    }
    return $xml;
}
Beispiel #2
0
/**
 * Get an array containing new comcode, and tempcode. The function wraps the normal comcode_to_tempcode function. The function will do attachment management, including deleting of attachments that have become unused due to editing of some comcode and removing of the reference.
 *
 * @param  LONG_TEXT		The unparsed comcode that references the attachments
 * @param  ID_TEXT		The type the attachment will be used for (e.g. download)
 * @param  ID_TEXT		The ID the attachment will be used for
 * @param  boolean		Whether we are only previewing the attachments (i.e. don't store them!)
 * @param  ?object		The database connection to use (NULL: standard site connection)
 * @param  ?boolean		Whether to insert it as an admin (any comcode parsing will be carried out with admin privileges) (NULL: autodetect)
 * @param  ?MEMBER		The member to use for ownership permissions (NULL: current member)
 * @return array			A map containing 'comcode' (after substitution for tying down the new attachments) and 'tempcode'
 */
function do_comcode_attachments($original_comcode, $type, $id, $previewing_only = false, $connection = NULL, $insert_as_admin = NULL, $for_member = NULL)
{
    require_lang('comcode');
    global $COMCODE_ATTACHMENTS;
    unset($COMCODE_ATTACHMENTS[$id]);
    // In case we have some kind of conflict
    if (is_null($connection)) {
        $connection = $GLOBALS['SITE_DB'];
    }
    if ($for_member !== NULL) {
        $member = $for_member;
        if (is_null($insert_as_admin)) {
            $insert_as_admin = false;
        }
    } else {
        if (function_exists('get_member')) {
            $member = get_member();
            if (is_null($insert_as_admin)) {
                $insert_as_admin = false;
            }
        } else {
            $member = 0;
            if (is_null($insert_as_admin)) {
                $insert_as_admin = true;
            }
        }
    }
    $comcode_text = substr($original_comcode, 0, 8) != '<comcode';
    // Handle data URLs for attachment embedding
    if (function_exists('imagecreatefromstring')) {
        $matches = array();
        $matches2 = array();
        $num_matches = preg_match_all('#<img[^<>]*src="data:image/\\w+;base64,([^"]*)"[^<>]*>#', $original_comcode, $matches);
        $num_matches2 = preg_match_all('#\\[img[^\\[\\]]*\\]data:image/\\w+;base64,([^"]*)\\[/img\\]#', $original_comcode, $matches2);
        for ($i = 0; $i < $num_matches2; $i++) {
            $matches[0][$num_matches] = $matches2[0][$i];
            $matches[1][$num_matches] = $matches2[1][$i];
            $num_matches++;
        }
        for ($i = 0; $i < $num_matches; $i++) {
            if (strpos($original_comcode, $matches[0][$i]) !== false) {
                $data = @base64_decode($matches[1][$i]);
                if ($data !== false && function_exists('imagepng')) {
                    $image = @imagecreatefromstring($data);
                    if ($image !== false) {
                        do {
                            $new_filename = uniqid('', true) . '.png';
                            $new_path = get_custom_file_base() . '/uploads/attachments/' . $new_filename;
                        } while (file_exists($new_path));
                        imagepng($image, $new_path);
                        $attachment_id = $GLOBALS['SITE_DB']->query_insert('attachments', array('a_member_id' => get_member(), 'a_file_size' => strlen($data), 'a_url' => 'uploads/attachments/' . $new_filename, 'a_thumb_url' => '', 'a_original_filename' => basename($new_filename), 'a_num_downloads' => 0, 'a_last_downloaded_time' => time(), 'a_description' => '', 'a_add_time' => time()), true);
                        $GLOBALS['SITE_DB']->query_insert('attachment_refs', array('r_referer_type' => $type, 'r_referer_id' => $id, 'a_id' => $attachment_id));
                        $original_comcode = str_replace($matches[0][$i], '[attachment type="inline" thumb="0"]' . strval($attachment_id) . '[/attachment]', $original_comcode);
                    }
                }
            }
        }
    }
    global $ATTACHMENTS_ALREADY_REFERENCED;
    $old_already = $ATTACHMENTS_ALREADY_REFERENCED;
    $ATTACHMENTS_ALREADY_REFERENCED = array();
    $before = $connection->query_select('attachment_refs', array('a_id', 'id'), array('r_referer_type' => $type, 'r_referer_id' => $id));
    foreach ($before as $ref) {
        $ATTACHMENTS_ALREADY_REFERENCED[$ref['a_id']] = 1;
    }
    $has_one = false;
    $may_have_one = false;
    foreach ($_POST as $key => $value) {
        if (preg_match('#^hidFileID\\_#i', $key) != 0) {
            require_code('uploads');
            $may_have_one = is_swf_upload();
        }
    }
    if ($may_have_one) {
        require_code('uploads');
        is_swf_upload(true);
        require_code('comcode_from_html');
        $original_comcode = preg_replace_callback('#<input [^>]*class="ocp_keep_ui_controlled" [^>]*title="([^"]*)" [^>]*type="text" [^>]*value="[^"]*"[^>]*/?' . '>#siU', 'debuttonise', $original_comcode);
    }
    $myfile = mixed();
    foreach ($_FILES as $key => $file) {
        $matches = array();
        if (($may_have_one && is_swf_upload() || is_uploaded_file($file['tmp_name'])) && preg_match('#file(\\d+)#', $key, $matches) != 0) {
            $has_one = true;
            $atype = post_param('attachmenttype' . $matches[1], '');
            $is_extract = preg_match('#\\[attachment [^\\]]*type="\\w+_extract"[^\\]]*\\]new_' . $matches[1] . '\\[/#', $original_comcode) != 0 || preg_match('#<attachment [^>]*type="\\w+_extract"[^>]*>new_' . $matches[1] . '</#', $original_comcode) != 0;
            if (substr($atype, -8) == '_extract' || $is_extract) {
                require_code('uploads');
                require_code('files');
                require_code('files2');
                $thumb = preg_match('#\\[(attachment|attachment_safe) [^\\]]*thumb="1"[^\\]]*\\]new_' . $matches[1] . '\\[/#', $original_comcode) != 0 || preg_match('#<(attachment|attachment_safe) [^>]*thumb="1"[^>]*>new_' . $matches[1] . '</#', $original_comcode) != 0;
                $arcext = get_file_extension($_FILES[$key]['name']);
                if ($arcext == 'tar' || $arcext == 'zip') {
                    if ($arcext == 'tar') {
                        require_code('tar');
                        $myfile = tar_open($file['tmp_name'], 'rb');
                        $dir = tar_get_directory($myfile, true);
                    } elseif ($arcext == 'zip') {
                        if (!function_exists('zip_open') && get_option('unzip_cmd') == '') {
                            warn_exit(do_lang_tempcode('ZIP_NOT_ENABLED'));
                        }
                        if (!function_exists('zip_open')) {
                            require_code('m_zip');
                            $mzip = true;
                        } else {
                            $mzip = false;
                        }
                        $myfile = zip_open($file['tmp_name']);
                        if (is_integer($myfile)) {
                            require_code('failure');
                            warn_exit(zip_error($myfile, $mzip));
                        }
                        $dir = array();
                        while (($zip_entry = zip_read($myfile)) !== false) {
                            $dir[] = array('zip_entry' => $zip_entry, 'path' => zip_entry_name($zip_entry), 'size' => zip_entry_filesize($zip_entry));
                        }
                    }
                    if (count($dir) > 100) {
                        require_code('site');
                        attach_message(do_lang_tempcode('TOO_MANY_FILES_TO_EXTRACT'), 'warn');
                    } else {
                        foreach ($dir as $entry) {
                            if (substr($entry['path'], -1) == '/') {
                                continue;
                            }
                            // Ignore folders
                            $_file = preg_replace('#\\..*\\.#', '.', basename($entry['path']));
                            if (!check_extension($_file, false, NULL, true)) {
                                continue;
                            }
                            if (should_ignore_file($entry['path'], IGNORE_ACCESS_CONTROLLERS | IGNORE_HIDDEN_FILES)) {
                                continue;
                            }
                            $place = get_custom_file_base() . '/uploads/attachments/' . $_file;
                            $i = 2;
                            // Hunt with sensible names until we don't get a conflict
                            while (file_exists($place)) {
                                $_file = strval($i) . basename($entry['path']);
                                $place = get_custom_file_base() . '/uploads/attachments/' . $_file;
                                $i++;
                            }
                            $i = 2;
                            $_file_thumb = basename($entry['path']);
                            $place_thumb = get_custom_file_base() . '/uploads/attachments_thumbs/' . $_file_thumb;
                            // Hunt with sensible names until we don't get a conflict
                            while (file_exists($place_thumb)) {
                                $_file_thumb = strval($i) . basename($entry['path']);
                                $place_thumb = get_custom_file_base() . '/uploads/attachments_thumbs/' . $_file_thumb;
                                $i++;
                            }
                            if ($arcext == 'tar') {
                                $file_details = tar_get_file($myfile, $entry['path'], false, $place);
                            } elseif ($arcext == 'zip') {
                                zip_entry_open($myfile, $entry['zip_entry']);
                                $file_details = array('size' => $entry['size']);
                                $out_file = @fopen($place, 'wb') or intelligent_write_error($place);
                                $more = mixed();
                                do {
                                    $more = zip_entry_read($entry['zip_entry']);
                                    if ($more !== false) {
                                        if (fwrite($out_file, $more) < strlen($more)) {
                                            warn_exit(do_lang_tempcode('COULD_NOT_SAVE_FILE'));
                                        }
                                    }
                                } while ($more !== false && $more != '');
                                fclose($out_file);
                                zip_entry_close($entry['zip_entry']);
                            }
                            $description = do_lang('EXTRACTED_FILE');
                            if (strpos($entry['path'], '/') !== false) {
                                $description = do_lang('EXTRACTED_FILE_PATH', dirname($entry['path']));
                            }
                            // Thumbnail
                            $thumb_url = '';
                            require_code('images');
                            if (is_image($_file)) {
                                $gd = get_option('is_on_gd') == '1' && function_exists('imagetypes');
                                if ($gd) {
                                    require_code('images');
                                    if (!is_saveable_image($_file)) {
                                        $ext = '.png';
                                    } else {
                                        $ext = '.' . get_file_extension($_file);
                                    }
                                    $thumb_url = 'uploads/attachments_thumbs/' . $_file_thumb;
                                    convert_image(get_custom_base_url() . '/uploads/attachments/' . $_file, $place_thumb, -1, -1, intval(get_option('thumb_width')), true, NULL, false, true);
                                    if ($connection->connection_write != $GLOBALS['SITE_DB']->connection_write) {
                                        $thumb_url = get_custom_base_url() . '/' . $thumb_url;
                                    }
                                } else {
                                    $thumb_url = 'uploads/attachments/' . $_file;
                                }
                            }
                            $url = 'uploads/attachments/' . $_file;
                            if (addon_installed('galleries')) {
                                require_code('images');
                                if (is_video($url) && $connection->connection_read == $GLOBALS['SITE_DB']->connection_read) {
                                    require_code('transcoding');
                                    $url = transcode_video($url, 'attachments', 'a_url', 'a_original_filename', NULL, NULL);
                                }
                            }
                            $attachment_id = $connection->query_insert('attachments', array('a_member_id' => get_member(), 'a_file_size' => $file_details['size'], 'a_url' => $url, 'a_thumb_url' => $thumb_url, 'a_original_filename' => basename($entry['path']), 'a_num_downloads' => 0, 'a_last_downloaded_time' => time(), 'a_description' => $description, 'a_add_time' => time()), true);
                            $connection->query_insert('attachment_refs', array('r_referer_type' => $type, 'r_referer_id' => $id, 'a_id' => $attachment_id));
                            if ($comcode_text) {
                                $original_comcode .= chr(10) . chr(10) . '[attachment type="' . comcode_escape(str_replace('_extract', '', $atype)) . '" description="' . comcode_escape($description) . '" thumb="' . ($thumb ? '1' : '0') . '"]' . strval($attachment_id) . '[/attachment]';
                            } else {
                                require_code('comcode_xml');
                                //$original_comcode.=chr(10).chr(10).'<attachment type="'.comcode_escape(str_replace('_extract','',$atype)).'" thumb="'.($thumb?'1':'0').'"><attachmentDescription>'.comcode_text__to__comcode_xml($description).'</attachmentDescription>'.strval($attachment_id).'</attachment>';			Would go in bad spot
                            }
                        }
                    }
                    if ($arcext == 'tar') {
                        tar_close($myfile);
                    } elseif ($arcext == 'zip') {
                        zip_close($myfile);
                    }
                }
            } else {
                if (strpos($original_comcode, ']new_' . $matches[1] . '[/attachment]') === false && strpos($original_comcode, '>new_' . $matches[1] . '</attachment>') === false && strpos($original_comcode, ']new_' . $matches[1] . '[/attachment_safe]') === false && strpos($original_comcode, '>new_' . $matches[1] . '</attachment_safe>') === false) {
                    if (preg_match('#\\]\\d+\\[/attachment\\]#', $original_comcode) == 0 && preg_match('#>\\d+</attachment>#', $original_comcode) == 0) {
                        if ($comcode_text) {
                            $original_comcode .= chr(10) . chr(10) . '[attachment]new_' . $matches[1] . '[/attachment]';
                        } else {
                            //$original_comcode.=chr(10).chr(10).'<attachment>new_'.$matches[1].'</attachment>';		Would go in bad spot
                        }
                    }
                }
            }
        }
    }
    global $LAX_COMCODE;
    $temp = $LAX_COMCODE;
    if ($has_one) {
        $LAX_COMCODE = true;
    }
    // We don't want a simple syntax error to cause us to lose our attachments
    $tempcode = comcode_to_tempcode($original_comcode, $member, $insert_as_admin, 60, $id, $connection, false, false, false, false, false, NULL, $for_member);
    $LAX_COMCODE = $temp;
    $ATTACHMENTS_ALREADY_REFERENCED = $old_already;
    /*if ((array_key_exists($id,$COMCODE_ATTACHMENTS)) && (array_key_exists(0,$COMCODE_ATTACHMENTS[$id])))
    	{
    		$original_comcode=$COMCODE_ATTACHMENTS[$id][0]['comcode'];
    	}*/
    $new_comcode = $original_comcode;
    if (array_key_exists($id, $COMCODE_ATTACHMENTS)) {
        $ids_present = array();
        for ($i = 0; $i < count($COMCODE_ATTACHMENTS[$id]); $i++) {
            $attachment = $COMCODE_ATTACHMENTS[$id][$i];
            // If it's a new one, we need to change the comcode to reference the ID we made for it
            if ($attachment['type'] == 'new') {
                $marker = $attachment['marker'];
                //				echo $marker.'!'.$new_comcode;
                $a_id = $attachment['id'];
                $old_length = strlen($new_comcode);
                // Search backwards from $marker
                $tag_end_start = $marker - strlen('[/' . $attachment['tag_type'] . ']');
                // </attachment> would be correct if it is Comcode-XML, but they have the same length, so it's irrelevant
                $tag_start_end = $tag_end_start;
                while ($tag_start_end > 1 && (!isset($new_comcode[$tag_start_end - 1]) || $new_comcode[$tag_start_end - 1] != ']' && $new_comcode[$tag_start_end - 1] != '>')) {
                    $tag_start_end--;
                }
                $param_keep = substr($new_comcode, 0, $tag_start_end - 1);
                $end_keep = substr($new_comcode, $tag_end_start);
                if ($comcode_text) {
                    $new_comcode = $param_keep;
                    if (strpos(substr($param_keep, strrpos($param_keep, '[')), ' type=') === false) {
                        $new_comcode .= ' type="' . comcode_escape($attachment['attachmenttype']) . '"';
                    }
                    if (strpos(substr($param_keep, strrpos($param_keep, '[')), ' description=') === false) {
                        $new_comcode .= ' description="' . comcode_escape($attachment['description']) . '"';
                    }
                    $new_comcode .= ']' . strval($a_id) . $end_keep;
                } else {
                    require_code('comcode_xml');
                    $new_comcode = $param_keep;
                    if (strpos(substr($param_keep, strrpos($param_keep, '<')), ' type=') === false) {
                        $new_comcode .= ' type="' . comcode_escape($attachment['attachmenttype']);
                    }
                    $new_comcode .= '">';
                    if (strpos(substr($param_keep, strrpos($param_keep, '<')), ' description=') === false) {
                        require_code('comcode_xml');
                        $new_comcode .= '<attachmentDescription>' . comcode_text__to__comcode_xml($attachment['description'], true) . '</attachmentDescription>';
                    }
                    $new_comcode .= strval($a_id) . $end_keep;
                }
                //				echo $new_comcode.'<br />!<br />';
                // Update other attachment markers
                $dif = strlen($new_comcode) - $old_length;
                for ($j = $i + 1; $j < count($COMCODE_ATTACHMENTS[$id]); $j++) {
                    //					echo $COMCODE_ATTACHMENTS[$id][$i]['marker'].'!';
                    $COMCODE_ATTACHMENTS[$id][$j]['marker'] += $dif;
                }
                if (!is_null($type)) {
                    $connection->query_insert('attachment_refs', array('r_referer_type' => $type, 'r_referer_id' => $id, 'a_id' => $a_id));
                }
            } else {
                // (Re-)Reference it
                $connection->query_delete('attachment_refs', array('r_referer_type' => $type, 'r_referer_id' => $id, 'a_id' => $attachment['id']), '', 1);
                $connection->query_insert('attachment_refs', array('r_referer_type' => $type, 'r_referer_id' => $id, 'a_id' => $attachment['id']));
            }
            $ids_present[] = $attachment['id'];
        }
        if (!$previewing_only && get_value('disable_attachment_cleanup') !== '1') {
            // Clear any de-referenced attachments
            foreach ($before as $ref) {
                if (!in_array($ref['a_id'], $ids_present) && strpos($new_comcode, 'attachment.php?id=') === false && !multi_lang()) {
                    // Delete reference (as it's not actually in the new comcode!)
                    $connection->query_delete('attachment_refs', array('id' => $ref['id']), '', 1);
                    // Was that the last reference to this attachment? (if so -- delete attachment)
                    $test = $connection->query_value_null_ok('attachment_refs', 'id', array('a_id' => $ref['a_id']));
                    if (is_null($test)) {
                        require_code('attachments3');
                        _delete_attachment($ref['a_id'], $connection);
                    }
                }
            }
        }
    }
    return array('comcode' => $new_comcode, 'tempcode' => $tempcode);
}
Beispiel #3
0
/**
 * Export an ocPortal database row to an equivalent XML format.
 *
 * @param  ID_TEXT		Table to export
 * @param  array			DB row
 * @param  array			List of field definitions for the row
 * @param  ?ID_TEXT		SEO type code (NULL: N/A)
 * @param  ?ID_TEXT		Permission type code (NULL: N/A)
 * @param  ?ID_TEXT		ID field name (NULL: N/A)
 * @param  boolean		Whether to export Comcode as Comcode XML
 * @param  boolean		Whether to include the end tag for the row
 * @return string			Exported data in XML format
 */
function _export_xml_row($table, $row, $db_fields, $seo_type_code, $permissions_type_code, $id_field, $comcode_xml, $include_end = true)
{
    $xml_data = '';
    $inner = '';
    $fields = '';
    $auto_key_id = NULL;
    foreach ($db_fields as $field) {
        if ($field['m_table'] != $table) {
            continue;
        }
        $name = $field['m_name'];
        $value = '';
        if (strpos($field['m_type'], 'TRANS') !== false || $table == 'config' && $name == 'config_value' && $row[$name] != '' && strpos($row['the_type'], 'trans') !== false) {
            $translate_rows = $GLOBALS['SITE_DB']->query_select('translate', array('*'), array('id' => $row[$name]));
            foreach ($translate_rows as $t) {
                if ($comcode_xml && $t['text_parsed'] != '' && $t['text_original'] != '') {
                    $value = chr(10) . _tab(comcode_text__to__comcode_xml($t['text_original'])) . chr(10);
                } else {
                    $value = xmlentities($t['text_original']);
                }
                $inner .= _tab('<' . $name . ' language="' . xmlentities($t['language']) . '" importance_level="' . xmlentities(strval($t['importance_level'])) . '" source_user="******">' . $value . '</' . $name . '>') . chr(10);
            }
            if (strpos($field['m_type'], '*') !== false) {
                if ($field['m_type'] == '*AUTO') {
                    $auto_key_id = $field['m_name'];
                }
                $fields .= ' ' . $name . '="' . xmlentities(strval($row[$name])) . '"';
            }
        } else {
            if (!array_key_exists($name, $row)) {
                continue;
            }
            // Shouldn't happen, but corruption could lead to this
            switch (gettype($row[$name])) {
                case 'integer':
                    switch (str_replace('?', '', str_replace('*', '', $field['m_type']))) {
                        case 'TIME':
                            $value = strftime('%a, %d %b %Y %H:%M:%S %z', $row[$name]);
                            break;
                        default:
                            $value = strval($row[$name]);
                            break;
                    }
                    break;
                case 'double':
                    // float
                    $value = float_to_raw_string($row[$name]);
                    break;
                case 'NULL':
                    $value = '';
                    break;
                default:
                    $value = $row[$name];
                    break;
            }
            // Place data
            if (strpos($field['m_type'], '*') !== false) {
                if ($field['m_type'] == '*AUTO') {
                    $auto_key_id = $field['m_name'];
                }
                $fields .= ' ' . $name . '="' . xmlentities($value) . '"';
            } else {
                $inner .= _tab('<' . $name . '>' . xmlentities($value) . '</' . $name . '>') . chr(10);
            }
        }
    }
    // Assemble full row in XML format
    $xml_data .= chr(10) . chr(10);
    if (!is_null($auto_key_id)) {
        $xml_data .= '<!-- If copying to another site you may wish to remove the ' . $auto_key_id . ' attribute/value-pair so that an appropriate new key is chosen (otherwise could update the wrong record) -->' . chr(10);
    }
    $xml_data .= '<' . $table . $fields . '>' . chr(10);
    $xml_data .= $inner;
    // SEO
    if (!is_null($seo_type_code)) {
        $rows = $GLOBALS['SITE_DB']->query_select('seo_meta', array('*'), array('meta_for_type' => $seo_type_code, 'meta_for_id' => is_integer($row[$id_field]) ? strval($row[$id_field]) : $row[$id_field]), '', 1);
        if (array_key_exists(0, $rows)) {
            if (is_integer($rows[0]['meta_for_id'])) {
                $export_row = array('meta_for_id' => 'LAST_INSERT_ID_' . $table) + $rows[0];
            } else {
                $export_row = $rows[0];
            }
            $xml_data .= _tab(_export_xml_row('seo_meta', $export_row, $db_fields, NULL, NULL, NULL, $comcode_xml));
        }
    }
    // Permissions
    if (!is_null($permissions_type_code)) {
        $rows = $GLOBALS['SITE_DB']->query_select('group_category_access', array('*'), array('module_the_name' => $permissions_type_code, 'category_name' => is_integer($row[$id_field]) ? strval($row[$id_field]) : $row[$id_field]));
        foreach ($rows as $_row) {
            if (is_integer($_row['category_name'])) {
                $export_row = array('category_name' => 'LAST_INSERT_ID_' . $table) + $_row;
            } else {
                $export_row = $_row;
            }
            $xml_data .= _tab(_export_xml_row('group_category_access', $export_row, $db_fields, NULL, NULL, NULL, $comcode_xml));
        }
        $rows = $GLOBALS['SITE_DB']->query_select('gsp', array('*'), array('module_the_name' => $permissions_type_code, 'category_name' => is_integer($row[$id_field]) ? strval($row[$id_field]) : $row[$id_field]));
        foreach ($rows as $_row) {
            if (is_integer($_row['category_name'])) {
                $export_row = array('category_name' => 'LAST_INSERT_ID_' . $table) + $_row;
            } else {
                $export_row = $_row;
            }
            $xml_data .= _tab(_export_xml_row('gsp', $export_row, $db_fields, NULL, NULL, NULL, $comcode_xml));
        }
    }
    if ($include_end) {
        $xml_data .= '</' . $table . '>';
    }
    return $xml_data;
}
Beispiel #4
0
/**
 * AJAX script for HTML<>Comcode conversion (and Comcode-Text>Comcode-XML).
 */
function comcode_convert_script()
{
    header("Cache-Control: no-cache, must-revalidate");
    // HTTP/1.1
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    // Date in the past
    global $EXTRA_HEAD;
    if (!isset($EXTRA_HEAD)) {
        $EXTRA_HEAD = new ocp_tempcode();
    }
    $EXTRA_HEAD->attach('<meta name="robots" content="noindex" />');
    // XHTMLXHTML
    require_lang('comcode');
    convert_data_encodings(true);
    $data = post_param('data', NULL, false, false);
    if (is_null($data)) {
        $title = get_page_title('_COMCODE');
        $fields = new ocp_tempcode();
        require_code('form_templates');
        $fields->attach(form_input_huge(do_lang_tempcode('TEXT'), '', 'data', '', true));
        $fields->attach(form_input_tick('Convert HTML to Comcode', '', 'from_html', false));
        $fields->attach(form_input_tick('Convert to semihtml', '', 'semihtml', false));
        $fields->attach(form_input_tick('Lax mode (less parse rules)', '', 'lax', false));
        $hidden = new ocp_tempcode();
        $hidden->attach(form_input_hidden('to_comcode_xml', strval(either_param_integer('to_comcode_xml', 0))));
        $out2 = globalise(do_template('FORM_SCREEN', array('_GUID' => 'dd82970fa1196132e07049871c51aab7', 'TITLE' => $title, 'SUBMIT_NAME' => do_lang_tempcode('VIEW'), 'TEXT' => '', 'HIDDEN' => $hidden, 'URL' => find_script('comcode_convert', true), 'FIELDS' => $fields)), NULL, '', true);
        $out2->evaluate_echo();
        return;
    }
    $panel = either_param_integer('panel', NULL);
    if (!is_null($panel)) {
        global $TEMPCODE_SETGET;
        if ($panel == 0) {
            $TEMPCODE_SETGET['in_panel'] = '0';
        } else {
            $TEMPCODE_SETGET['in_panel'] = '1';
        }
    }
    if (either_param_integer('to_comcode_xml', 0) == 1) {
        require_code('comcode_conversion');
        $out = comcode_text__to__comcode_xml($data);
    } elseif (either_param_integer('from_html', 0) == 1) {
        require_code('comcode_from_html');
        $out = trim(semihtml_to_comcode($data));
    } else {
        if (either_param_integer('lax', 0) == 1) {
            $GLOBALS['LAX_COMCODE'] = true;
        }
        if (either_param_integer('is_semihtml', 0) == 1) {
            require_code('comcode_from_html');
            $data = semihtml_to_comcode($data);
        }
        $db = $GLOBALS['SITE_DB'];
        if (get_param_integer('forum_db', 0) == 1) {
            $db = $GLOBALS['FORUM_DB'];
        }
        $tpl = comcode_to_tempcode($data, get_member(), false, 60, NULL, $db, either_param_integer('semihtml', 0) == 1, false, false, false);
        $evaluated = $tpl->evaluate();
        $out = '';
        if ($evaluated != '') {
            if (get_param_integer('css', 0) == 1) {
                global $CSSS;
                unset($CSSS['global']);
                unset($CSSS['no_cache']);
                $out .= static_evaluate_tempcode(css_tempcode());
            }
            if (get_param_integer('javascript', 0) == 1) {
                global $JAVASCRIPTS;
                unset($JAVASCRIPTS['javascript']);
                unset($JAVASCRIPTS['javascript_staff']);
                $out .= static_evaluate_tempcode(javascript_tempcode());
            }
        }
        $out .= trim(trim($evaluated));
    }
    if (either_param_integer('fix_bad_html', 0) == 1) {
        require_code('xhtml');
        $new = xhtmlise_html($out, true);
        if (preg_replace('#<!--.*-->#Us', '', preg_replace('#\\s+#', '', $new)) != preg_replace('#<!--.*-->#Us', '', preg_replace('#\\s+#', '', $out))) {
            /*$myfile=fopen(get_file_base().'/a','wb');
            			fwrite($myfile,preg_replace('#<!--.*-->#Us','',preg_replace('#\s+#',chr(10),$new)));
            			fclose($myfile);
            
            			$myfile=fopen(get_file_base().'/b','wb');
            			fwrite($myfile,preg_replace('#<!--.*-->#Us','',preg_replace('#\s+#',chr(10),$out)));
            			fclose($myfile);*/
            $out = $new . do_lang('BROKEN_XHTML_FIXED');
        }
    }
    if (either_param_integer('keep_skip_rubbish', 0) == 0) {
        @ini_set('ocproducts.xss_detect', '0');
        $box_title = get_param('box_title', '');
        if (is_object($out)) {
            $out = $out->evaluate();
        }
        if ($box_title != '' && $out != '') {
            $out = static_evaluate_tempcode(put_in_standard_box(make_string_tempcode($out), $box_title));
        }
        header('Content-Type: text/xml');
        echo '<?xml version="1.0" encoding="' . get_charset() . '"?' . '>';
        echo '<request><result>';
        echo xmlentities($out);
        echo '</result></request>';
    } else {
        header('Content-type: text/plain; charset=' . get_charset());
        echo $out;
    }
}