Exemplo n.º 1
0
/**
 * Displays the body of the results table
 *
 * @uses    $_SESSION['tmp_user_values']['disp_direction']
 * @uses    $_SESSION['tmp_user_values']['repeat_cells']
 * @uses    $_SESSION['tmp_user_values']['max_rows']
 * @uses    $_SESSION['tmp_user_values']['display_text']
 * @uses    $_SESSION['tmp_user_values']['display_binary']
 * @uses    $_SESSION['tmp_user_values']['display_binary_as_hex']
 * @uses    $_SESSION['tmp_user_values']['display_blob']
 * @param   integer  the link id associated to the query which results have
 *                   to be displayed
 * @param   array    which elements to display
 * @param   array    the list of relations
 * @param   array    the analyzed query
 *
 * @return  boolean  always true
 *
 * @global  string   $db                the database name
 * @global  string   $table             the table name
 * @global  string   $goto              the URL to go back in case of errors
 * @global  string   $sql_query         the SQL query
 * @global  array    $fields_meta       the list of fields properties
 * @global  integer  $fields_cnt        the total number of fields returned by
 *                                      the SQL query
 * @global  array    $vertical_display  informations used with vertical display
 *                                      mode
 * @global  array    $highlight_columns column names to highlight
 * @global  array    $row               current row data
 *
 * @access  private
 *
 * @see     PMA_displayTable()
 */
function PMA_displayTableBody(&$dt_result, &$is_display, $map, $analyzed_sql)
{
    global $db, $table, $goto;
    global $sql_query, $fields_meta, $fields_cnt;
    global $vertical_display, $highlight_columns;
    global $row;
    // mostly because of browser transformations, to make the row-data accessible in a plugin
    $url_sql_query = $sql_query;
    // query without conditions to shorten URLs when needed, 200 is just
    // guess, it should depend on remaining URL length
    if (isset($analyzed_sql) && isset($analyzed_sql[0]) && isset($analyzed_sql[0]['querytype']) && $analyzed_sql[0]['querytype'] == 'SELECT' && strlen($sql_query) > 200) {
        $url_sql_query = 'SELECT ';
        if (isset($analyzed_sql[0]['queryflags']['distinct'])) {
            $url_sql_query .= ' DISTINCT ';
        }
        $url_sql_query .= $analyzed_sql[0]['select_expr_clause'];
        if (!empty($analyzed_sql[0]['from_clause'])) {
            $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause'];
        }
    }
    if (!is_array($map)) {
        $map = array();
    }
    $row_no = 0;
    $vertical_display['edit'] = array();
    $vertical_display['delete'] = array();
    $vertical_display['data'] = array();
    $vertical_display['row_delete'] = array();
    // Correction University of Virginia 19991216 in the while below
    // Previous code assumed that all tables have keys, specifically that
    // the phpMyAdmin GUI should support row delete/edit only for such
    // tables.
    // Although always using keys is arguably the prescribed way of
    // defining a relational table, it is not required. This will in
    // particular be violated by the novice.
    // We want to encourage phpMyAdmin usage by such novices. So the code
    // below has been changed to conditionally work as before when the
    // table being displayed has one or more keys; but to display
    // delete/edit options correctly for tables without keys.
    $odd_row = true;
    while ($row = PMA_DBI_fetch_row($dt_result)) {
        // lem9: "vertical display" mode stuff
        if ($row_no != 0 && $_SESSION['tmp_user_values']['repeat_cells'] != 0 && !($row_no % $_SESSION['tmp_user_values']['repeat_cells']) && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) {
            echo '<tr>' . "\n";
            if ($vertical_display['emptypre'] > 0) {
                echo '    <th colspan="' . $vertical_display['emptypre'] . '">' . "\n" . '        &nbsp;</th>' . "\n";
            }
            foreach ($vertical_display['desc'] as $val) {
                echo $val;
            }
            if ($vertical_display['emptyafter'] > 0) {
                echo '    <th colspan="' . $vertical_display['emptyafter'] . '">' . "\n" . '        &nbsp;</th>' . "\n";
            }
            echo '</tr>' . "\n";
        }
        // end if
        $class = $odd_row ? 'odd' : 'even';
        $odd_row = !$odd_row;
        if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') {
            // loic1: pointer code part
            echo '    <tr class="' . $class . '">' . "\n";
            $class = '';
        }
        // 1. Prepares the row
        // 1.1 Results from a "SELECT" statement -> builds the
        //     WHERE clause to use in links (a unique key if possible)
        /**
         * @todo $where_clause could be empty, for example a table
         *       with only one field and it's a BLOB; in this case,
         *       avoid to display the delete and edit links
         */
        list($where_clause, $clause_is_unique) = PMA_getUniqueCondition($dt_result, $fields_cnt, $fields_meta, $row);
        $where_clause_html = urlencode($where_clause);
        // 1.2 Defines the URLs for the modify/delete link(s)
        if ($is_display['edit_lnk'] != 'nn' || $is_display['del_lnk'] != 'nn') {
            // We need to copy the value or else the == 'both' check will always return true
            if ($GLOBALS['cfg']['PropertiesIconic'] === 'both') {
                $iconic_spacer = '<div class="nowrap">';
            } else {
                $iconic_spacer = '';
            }
            // 1.2.1 Modify link(s)
            if ($is_display['edit_lnk'] == 'ur') {
                // update row case
                $_url_params = array('db' => $db, 'table' => $table, 'where_clause' => $where_clause, 'clause_is_unique' => $clause_is_unique, 'sql_query' => $url_sql_query, 'goto' => 'sql.php');
                $edit_url = 'tbl_change.php' . PMA_generate_common_url($_url_params);
                $edit_str = PMA_getIcon('b_edit.png', $GLOBALS['strEdit'], true);
            }
            // end if (1.2.1)
            if (isset($GLOBALS['cfg']['Bookmark']['table']) && isset($GLOBALS['cfg']['Bookmark']['db']) && $table == $GLOBALS['cfg']['Bookmark']['table'] && $db == $GLOBALS['cfg']['Bookmark']['db'] && isset($row[1]) && isset($row[0])) {
                $_url_params = array('db' => $row[1], 'id_bookmark' => $row[0], 'action_bookmark' => '0', 'action_bookmark_all' => '1', 'SQL' => $GLOBALS['strExecuteBookmarked']);
                $bookmark_go = '<a href="import.php' . PMA_generate_common_url($_url_params) . ' " title="' . $GLOBALS['strExecuteBookmarked'] . '">';
                $bookmark_go .= PMA_getIcon('b_bookmark.png', $GLOBALS['strExecuteBookmarked'], true);
                $bookmark_go .= '</a>';
            } else {
                $bookmark_go = '';
            }
            // 1.2.2 Delete/Kill link(s)
            if ($is_display['del_lnk'] == 'dr') {
                // delete row case
                $_url_params = array('db' => $db, 'table' => $table, 'sql_query' => $url_sql_query, 'zero_rows' => $GLOBALS['strDeleted'], 'goto' => empty($goto) ? 'tbl_sql.php' : $goto);
                $lnk_goto = 'sql.php' . PMA_generate_common_url($_url_params, 'text');
                $del_query = 'DELETE FROM ' . PMA_backquote($db) . '.' . PMA_backquote($table) . ' WHERE ' . $where_clause . ($clause_is_unique ? '' : ' LIMIT 1');
                $_url_params = array('db' => $db, 'table' => $table, 'sql_query' => $del_query, 'zero_rows' => $GLOBALS['strDeleted'], 'goto' => $lnk_goto);
                $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
                $js_conf = 'DELETE FROM ' . PMA_jsFormat($db) . '.' . PMA_jsFormat($table) . ' WHERE ' . PMA_jsFormat($where_clause, false) . ($clause_is_unique ? '' : ' LIMIT 1');
                $del_str = PMA_getIcon('b_drop.png', $GLOBALS['strDelete'], true);
            } elseif ($is_display['del_lnk'] == 'kp') {
                // kill process case
                $_url_params = array('db' => $db, 'table' => $table, 'sql_query' => $url_sql_query, 'goto' => 'main.php');
                $lnk_goto = 'sql.php' . PMA_generate_common_url($_url_params, 'text');
                $_url_params = array('db' => 'mysql', 'sql_query' => 'KILL ' . $row[0], 'goto' => $lnk_goto);
                $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
                $del_query = 'KILL ' . $row[0];
                $js_conf = 'KILL ' . $row[0];
                $del_str = PMA_getIcon('b_drop.png', $GLOBALS['strKill'], true);
            }
            // end if (1.2.2)
            // 1.3 Displays the links at left if required
            if ($GLOBALS['cfg']['ModifyDeleteAtLeft'] && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) {
                $doWriteModifyAt = 'left';
                require './libraries/display_tbl_links.lib.php';
            }
            // end if (1.3)
        }
        // end if (1)
        // 2. Displays the rows' values
        for ($i = 0; $i < $fields_cnt; ++$i) {
            $meta = $fields_meta[$i];
            $pointer = $i;
            // garvin: See if this column should get highlight because it's used in the
            //  where-query.
            if (isset($highlight_columns) && (isset($highlight_columns[$meta->name]) || isset($highlight_columns[PMA_backquote($meta->name)]))) {
                $condition_field = true;
            } else {
                $condition_field = false;
            }
            $mouse_events = '';
            if ($_SESSION['tmp_user_values']['disp_direction'] == 'vertical' && (!isset($GLOBALS['printview']) || $GLOBALS['printview'] != '1')) {
                if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
                    $mouse_events .= ' onmouseover="setVerticalPointer(this, ' . $row_no . ', \'over\', \'odd\', \'even\', \'hover\', \'marked\');"' . ' onmouseout="setVerticalPointer(this, ' . $row_no . ', \'out\', \'odd\', \'even\', \'hover\', \'marked\');" ';
                }
                if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
                    $mouse_events .= ' onmousedown="setVerticalPointer(this, ' . $row_no . ', \'click\', \'odd\', \'even\', \'hover\', \'marked\'); setCheckboxColumn(\'id_rows_to_delete' . $row_no . '\');" ';
                } else {
                    $mouse_events .= ' onmousedown="setCheckboxColumn(\'id_rows_to_delete' . $row_no . '\');" ';
                }
            }
            // end if
            // garvin: Wrap MIME-transformations. [MIME]
            $default_function = 'default_function';
            // default_function
            $transform_function = $default_function;
            $transform_options = array();
            if ($GLOBALS['cfgRelation']['mimework'] && $GLOBALS['cfg']['BrowseMIME']) {
                if (isset($GLOBALS['mime_map'][$meta->name]['mimetype']) && isset($GLOBALS['mime_map'][$meta->name]['transformation']) && !empty($GLOBALS['mime_map'][$meta->name]['transformation'])) {
                    $include_file = $GLOBALS['mime_map'][$meta->name]['transformation'];
                    if (file_exists('./libraries/transformations/' . $include_file)) {
                        $transformfunction_name = str_replace('.inc.php', '', $GLOBALS['mime_map'][$meta->name]['transformation']);
                        require_once './libraries/transformations/' . $include_file;
                        if (function_exists('PMA_transformation_' . $transformfunction_name)) {
                            $transform_function = 'PMA_transformation_' . $transformfunction_name;
                            $transform_options = PMA_transformation_getOptions(isset($GLOBALS['mime_map'][$meta->name]['transformation_options']) ? $GLOBALS['mime_map'][$meta->name]['transformation_options'] : '');
                            $meta->mimetype = str_replace('_', '/', $GLOBALS['mime_map'][$meta->name]['mimetype']);
                        }
                    }
                    // end if file_exists
                }
                // end if transformation is set
            }
            // end if mime/transformation works.
            $_url_params = array('db' => $db, 'table' => $table, 'where_clause' => $where_clause, 'transform_key' => $meta->name);
            if (!empty($sql_query)) {
                $_url_params['sql_query'] = $url_sql_query;
            }
            $transform_options['wrapper_link'] = PMA_generate_common_url($_url_params);
            // n u m e r i c
            if ($meta->numeric == 1) {
                // lem9: if two fields have the same name (this is possible
                //       with self-join queries, for example), using $meta->name
                //       will show both fields NULL even if only one is NULL,
                //       so use the $pointer
                if (!isset($row[$i]) || is_null($row[$i])) {
                    $vertical_display['data'][$row_no][$i] = '    <td align="right"' . $mouse_events . ' class="' . $class . ($condition_field ? ' condition' : '') . '"><i>NULL</i></td>' . "\n";
                } elseif ($row[$i] != '') {
                    $nowrap = ' nowrap';
                    $where_comparison = ' = ' . $row[$i];
                    $vertical_display['data'][$row_no][$i] = '<td align="right"' . PMA_prepare_row_data($mouse_events, $class, $condition_field, $analyzed_sql, $meta, $map, $row[$i], $transform_function, $default_function, $nowrap, $where_comparison, $transform_options);
                } else {
                    $vertical_display['data'][$row_no][$i] = '    <td align="right"' . $mouse_events . ' class="' . $class . ' nowrap' . ($condition_field ? ' condition' : '') . '">&nbsp;</td>' . "\n";
                }
                //  b l o b
            } elseif (stristr($meta->type, 'BLOB')) {
                // loic1 : PMA_mysql_fetch_fields returns BLOB in place of
                // TEXT fields type so we have to ensure it's really a BLOB
                $field_flags = PMA_DBI_field_flags($dt_result, $i);
                if (stristr($field_flags, 'BINARY')) {
                    // rajk - for blobstreaming
                    $bs_reference_exists = $allBSTablesExist = FALSE;
                    // load PMA configuration
                    $PMA_Config = $_SESSION['PMA_Config'];
                    // if PMA configuration exists
                    if ($PMA_Config) {
                        // load BS variables
                        $pluginsExist = $PMA_Config->get('BLOBSTREAMING_PLUGINS_EXIST');
                        // if BS plugins exist
                        if ($pluginsExist) {
                            // load BS databases
                            $bs_tables = $PMA_Config->get('BLOBSTREAMABLE_DATABASES');
                            // if BS db array and specified db string not empty and valid
                            if (!empty($bs_tables) && strlen($db) > 0) {
                                $bs_tables = $bs_tables[$db];
                                if (isset($bs_tables)) {
                                    $allBSTablesExist = TRUE;
                                    // check if BS tables exist for given database
                                    foreach ($bs_tables as $table_key => $bs_tbl) {
                                        if (!$bs_tables[$table_key]['Exists']) {
                                            $allBSTablesExist = FALSE;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // if necessary BS tables exist
                    if ($allBSTablesExist) {
                        $bs_reference_exists = PMA_BS_ReferenceExists($row[$i], $db);
                    }
                    // if valid BS reference exists
                    if ($bs_reference_exists) {
                        $blobtext = PMA_BS_CreateReferenceLink($row[$i], $db);
                    } else {
                        $blobtext = PMA_handle_non_printable_contents('BLOB', isset($row[$i]) ? $row[$i] : '', $transform_function, $transform_options, $default_function, $meta);
                    }
                    $vertical_display['data'][$row_no][$i] = '    <td align="left"' . $mouse_events . ' class="' . $class . ($condition_field ? ' condition' : '') . '">' . $blobtext . '</td>';
                    unset($blobtext);
                    // not binary:
                } else {
                    if (!isset($row[$i]) || is_null($row[$i])) {
                        $vertical_display['data'][$row_no][$i] = '    <td' . $mouse_events . ' class="' . $class . ($condition_field ? ' condition' : '') . '"><i>NULL</i></td>' . "\n";
                    } elseif ($row[$i] != '') {
                        // garvin: if a transform function for blob is set, none of these replacements will be made
                        if (PMA_strlen($row[$i]) > $GLOBALS['cfg']['LimitChars'] && $_SESSION['tmp_user_values']['display_text'] == 'P') {
                            $row[$i] = PMA_substr($row[$i], 0, $GLOBALS['cfg']['LimitChars']) . '...';
                        }
                        // loic1: displays all space characters, 4 space
                        // characters for tabulations and <cr>/<lf>
                        $row[$i] = $default_function != $transform_function ? $transform_function($row[$i], $transform_options, $meta) : $default_function($row[$i], array(), $meta);
                        $vertical_display['data'][$row_no][$i] = '    <td' . $mouse_events . ' class="' . $class . ($condition_field ? ' condition' : '') . '">' . $row[$i] . '</td>' . "\n";
                    } else {
                        $vertical_display['data'][$row_no][$i] = '    <td' . $mouse_events . ' class="' . $class . ($condition_field ? ' condition' : '') . '">&nbsp;</td>' . "\n";
                    }
                }
                // n o t   n u m e r i c   a n d   n o t   B L O B
            } else {
                if (!isset($row[$i]) || is_null($row[$i])) {
                    $vertical_display['data'][$row_no][$i] = '    <td' . $mouse_events . ' class="' . $class . ($condition_field ? ' condition' : '') . '"><i>NULL</i></td>' . "\n";
                } elseif ($row[$i] != '') {
                    // loic1: support blanks in the key
                    $relation_id = $row[$i];
                    // nijel: Cut all fields to $GLOBALS['cfg']['LimitChars']
                    // lem9: (unless it's a link-type transformation)
                    if (PMA_strlen($row[$i]) > $GLOBALS['cfg']['LimitChars'] && $_SESSION['tmp_user_values']['display_text'] == 'P' && !strpos($transform_function, 'link') === true) {
                        $row[$i] = PMA_substr($row[$i], 0, $GLOBALS['cfg']['LimitChars']) . '...';
                    }
                    // loic1: displays special characters from binaries
                    $field_flags = PMA_DBI_field_flags($dt_result, $i);
                    if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) {
                        $row[$i] = PMA_printable_bit_value($row[$i], $meta->length);
                    } elseif (stristr($field_flags, 'BINARY') && $meta->type == 'string') {
                        if ($_SESSION['tmp_user_values']['display_binary'] || isset($GLOBALS['is_analyse']) && $GLOBALS['is_analyse']) {
                            // user asked to see the real contents of BINARY
                            // fields, or we detected a PROCEDURE ANALYSE in
                            // the query (results are reported as being
                            // binary strings)
                            if ($_SESSION['tmp_user_values']['display_binary_as_hex']) {
                                $row[$i] = bin2hex($row[$i]);
                            } else {
                                $row[$i] = htmlspecialchars(PMA_replace_binary_contents($row[$i]));
                            }
                        } else {
                            // we show the BINARY message and field's size
                            // (or maybe use a transformation)
                            $row[$i] = PMA_handle_non_printable_contents('BINARY', $row[$i], $transform_function, $transform_options, $default_function, $meta);
                        }
                    }
                    // garvin: transform functions may enable no-wrapping:
                    $function_nowrap = $transform_function . '_nowrap';
                    $bool_nowrap = $default_function != $transform_function && function_exists($function_nowrap) ? $function_nowrap($transform_options) : false;
                    // loic1: do not wrap if date field type
                    $nowrap = preg_match('@DATE|TIME@i', $meta->type) || $bool_nowrap ? ' nowrap' : '';
                    $where_comparison = ' = \'' . PMA_sqlAddslashes($row[$i]) . '\'';
                    $vertical_display['data'][$row_no][$i] = '<td ' . PMA_prepare_row_data($mouse_events, $class, $condition_field, $analyzed_sql, $meta, $map, $row[$i], $transform_function, $default_function, $nowrap, $where_comparison, $transform_options);
                } else {
                    $vertical_display['data'][$row_no][$i] = '    <td' . $mouse_events . ' class="' . $class . ($condition_field ? ' condition' : '') . '">&nbsp;</td>' . "\n";
                }
            }
            // lem9: output stored cell
            if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') {
                echo $vertical_display['data'][$row_no][$i];
            }
            if (isset($vertical_display['rowdata'][$i][$row_no])) {
                $vertical_display['rowdata'][$i][$row_no] .= $vertical_display['data'][$row_no][$i];
            } else {
                $vertical_display['rowdata'][$i][$row_no] = $vertical_display['data'][$row_no][$i];
            }
        }
        // end for (2)
        // 3. Displays the modify/delete links on the right if required
        if ($GLOBALS['cfg']['ModifyDeleteAtRight'] && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) {
            $doWriteModifyAt = 'right';
            require './libraries/display_tbl_links.lib.php';
        }
        // end if (3)
        if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') {
            ?>
</tr>
            <?php 
        }
        // end if
        // 4. Gather links of del_urls and edit_urls in an array for later
        //    output
        if (!isset($vertical_display['edit'][$row_no])) {
            $vertical_display['edit'][$row_no] = '';
            $vertical_display['delete'][$row_no] = '';
            $vertical_display['row_delete'][$row_no] = '';
        }
        $column_style_vertical = '';
        if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
            $column_style_vertical .= ' onmouseover="setVerticalPointer(this, ' . $row_no . ', \'over\', \'odd\', \'even\', \'hover\', \'marked\');"' . ' onmouseout="setVerticalPointer(this, ' . $row_no . ', \'out\', \'odd\', \'even\', \'hover\', \'marked\');"';
        }
        $column_marker_vertical = '';
        if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
            $column_marker_vertical .= 'setVerticalPointer(this, ' . $row_no . ', \'click\', \'odd\', \'even\', \'hover\', \'marked\');';
        }
        if (!empty($del_url) && $is_display['del_lnk'] != 'kp') {
            $vertical_display['row_delete'][$row_no] .= '    <td align="center" class="' . $class . '" ' . $column_style_vertical . '>' . "\n" . '        <input type="checkbox" id="id_rows_to_delete' . $row_no . '[%_PMA_CHECKBOX_DIR_%]" name="rows_to_delete[' . $where_clause_html . ']"' . ' onclick="' . $column_marker_vertical . 'copyCheckboxesRange(\'rowsDeleteForm\', \'id_rows_to_delete' . $row_no . '\',\'[%_PMA_CHECKBOX_DIR_%]\');"' . ' value="' . htmlspecialchars($del_query) . '" ' . (isset($GLOBALS['checkall']) ? 'checked="checked"' : '') . ' />' . "\n" . '    </td>' . "\n";
        } else {
            unset($vertical_display['row_delete'][$row_no]);
        }
        if (isset($edit_url)) {
            $vertical_display['edit'][$row_no] .= '    <td align="center" class="' . $class . '" ' . $column_style_vertical . '>' . "\n" . PMA_linkOrButton($edit_url, $edit_str, array(), false) . $bookmark_go . '    </td>' . "\n";
        } else {
            unset($vertical_display['edit'][$row_no]);
        }
        if (isset($del_url)) {
            $vertical_display['delete'][$row_no] .= '    <td align="center" class="' . $class . '" ' . $column_style_vertical . '>' . "\n" . PMA_linkOrButton($del_url, $del_str, isset($js_conf) ? $js_conf : '', false) . '    </td>' . "\n";
        } else {
            unset($vertical_display['delete'][$row_no]);
        }
        echo $_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped' ? "\n" : '';
        $row_no++;
    }
    // end while
    // this is needed by PMA_displayTable() to generate the proper param
    // in the multi-edit and multi-delete form
    return $clause_is_unique;
}
Exemplo n.º 2
0
/**
 * Displays the body of the results table
 *
 * @uses    $_SESSION['tmp_user_values']['disp_direction']
 * @uses    $_SESSION['tmp_user_values']['repeat_cells']
 * @uses    $_SESSION['tmp_user_values']['max_rows']
 * @uses    $_SESSION['tmp_user_values']['display_text']
 * @uses    $_SESSION['tmp_user_values']['display_binary']
 * @uses    $_SESSION['tmp_user_values']['display_binary_as_hex']
 * @uses    $_SESSION['tmp_user_values']['display_blob']
 * @param   integer  the link id associated to the query which results have
 *                   to be displayed
 * @param   array    which elements to display
 * @param   array    the list of relations
 * @param   array    the analyzed query
 *
 * @return  boolean  always true
 *
 * @global  string   $db                the database name
 * @global  string   $table             the table name
 * @global  string   $goto              the URL to go back in case of errors
 * @global  string   $sql_query         the SQL query
 * @global  array    $fields_meta       the list of fields properties
 * @global  integer  $fields_cnt        the total number of fields returned by
 *                                      the SQL query
 * @global  array    $vertical_display  informations used with vertical display
 *                                      mode
 * @global  array    $highlight_columns column names to highlight
 * @global  array    $row               current row data
 *
 * @access  private
 *
 * @see     PMA_displayTable()
 */
function PMA_displayTableBody(&$dt_result, &$is_display, $map, $analyzed_sql)
{
    global $db, $table, $goto;
    global $sql_query, $fields_meta, $fields_cnt;
    global $vertical_display, $highlight_columns;
    global $row;
    // mostly because of browser transformations, to make the row-data accessible in a plugin
    $url_sql_query = $sql_query;
    // query without conditions to shorten URLs when needed, 200 is just
    // guess, it should depend on remaining URL length
    if (isset($analyzed_sql) && isset($analyzed_sql[0]) && isset($analyzed_sql[0]['querytype']) && $analyzed_sql[0]['querytype'] == 'SELECT' && strlen($sql_query) > 200) {
        $url_sql_query = 'SELECT ';
        if (isset($analyzed_sql[0]['queryflags']['distinct'])) {
            $url_sql_query .= ' DISTINCT ';
        }
        $url_sql_query .= $analyzed_sql[0]['select_expr_clause'];
        if (!empty($analyzed_sql[0]['from_clause'])) {
            $url_sql_query .= ' FROM ' . $analyzed_sql[0]['from_clause'];
        }
    }
    if (!is_array($map)) {
        $map = array();
    }
    $row_no = 0;
    $vertical_display['edit'] = array();
    $vertical_display['copy'] = array();
    $vertical_display['delete'] = array();
    $vertical_display['data'] = array();
    $vertical_display['row_delete'] = array();
    // name of the class added to all inline editable elements
    $inline_edit_class = 'inline_edit';
    // Correction University of Virginia 19991216 in the while below
    // Previous code assumed that all tables have keys, specifically that
    // the phpMyAdmin GUI should support row delete/edit only for such
    // tables.
    // Although always using keys is arguably the prescribed way of
    // defining a relational table, it is not required. This will in
    // particular be violated by the novice.
    // We want to encourage phpMyAdmin usage by such novices. So the code
    // below has been changed to conditionally work as before when the
    // table being displayed has one or more keys; but to display
    // delete/edit options correctly for tables without keys.
    $odd_row = true;
    while ($row = PMA_DBI_fetch_row($dt_result)) {
        // "vertical display" mode stuff
        if ($row_no != 0 && $_SESSION['tmp_user_values']['repeat_cells'] != 0 && !($row_no % $_SESSION['tmp_user_values']['repeat_cells']) && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) {
            echo '<tr>' . "\n";
            if ($vertical_display['emptypre'] > 0) {
                echo '    <th colspan="' . $vertical_display['emptypre'] . '">' . "\n" . '        &nbsp;</th>' . "\n";
            }
            foreach ($vertical_display['desc'] as $val) {
                echo $val;
            }
            if ($vertical_display['emptyafter'] > 0) {
                echo '    <th colspan="' . $vertical_display['emptyafter'] . '">' . "\n" . '        &nbsp;</th>' . "\n";
            }
            echo '</tr>' . "\n";
        }
        // end if
        $alternating_color_class = $odd_row ? 'odd' : 'even';
        $odd_row = !$odd_row;
        if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') {
            // pointer code part
            echo '<tr class="' . $alternating_color_class . '">';
        }
        // 1. Prepares the row
        // 1.1 Results from a "SELECT" statement -> builds the
        //     WHERE clause to use in links (a unique key if possible)
        /**
         * @todo $where_clause could be empty, for example a table
         *       with only one field and it's a BLOB; in this case,
         *       avoid to display the delete and edit links
         */
        list($where_clause, $clause_is_unique) = PMA_getUniqueCondition($dt_result, $fields_cnt, $fields_meta, $row);
        $where_clause_html = urlencode($where_clause);
        // 1.2 Defines the URLs for the modify/delete link(s)
        if ($is_display['edit_lnk'] != 'nn' || $is_display['del_lnk'] != 'nn') {
            // We need to copy the value or else the == 'both' check will always return true
            if ($GLOBALS['cfg']['PropertiesIconic'] === 'both') {
                $iconic_spacer = '<div class="nowrap">';
            } else {
                $iconic_spacer = '';
            }
            // 1.2.1 Modify link(s)
            if ($is_display['edit_lnk'] == 'ur') {
                // update row case
                $_url_params = array('db' => $db, 'table' => $table, 'where_clause' => $where_clause, 'clause_is_unique' => $clause_is_unique, 'sql_query' => $url_sql_query, 'goto' => 'sql.php');
                $edit_url = 'tbl_change.php' . PMA_generate_common_url($_url_params + array('default_action' => 'update'));
                $copy_url = 'tbl_change.php' . PMA_generate_common_url($_url_params + array('default_action' => 'insert'));
                $edit_str = PMA_getIcon('b_edit.png', __('Edit'), true);
                $copy_str = PMA_getIcon('b_insrow.png', __('Copy'), true);
                // Class definitions required for inline editing jQuery scripts
                $edit_anchor_class = "edit_row_anchor";
                if ($clause_is_unique == 0) {
                    $edit_anchor_class .= ' nonunique';
                }
            }
            // end if (1.2.1)
            // 1.2.2 Delete/Kill link(s)
            if ($is_display['del_lnk'] == 'dr') {
                // delete row case
                $_url_params = array('db' => $db, 'table' => $table, 'sql_query' => $url_sql_query, 'message_to_show' => __('The row has been deleted'), 'goto' => empty($goto) ? 'tbl_sql.php' : $goto);
                $lnk_goto = 'sql.php' . PMA_generate_common_url($_url_params, 'text');
                $del_query = 'DELETE FROM ' . PMA_backquote($db) . '.' . PMA_backquote($table) . ' WHERE ' . $where_clause . ($clause_is_unique ? '' : ' LIMIT 1');
                $_url_params = array('db' => $db, 'table' => $table, 'sql_query' => $del_query, 'message_to_show' => __('The row has been deleted'), 'goto' => $lnk_goto);
                $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
                $js_conf = 'DELETE FROM ' . PMA_jsFormat($db) . '.' . PMA_jsFormat($table) . ' WHERE ' . PMA_jsFormat($where_clause, false) . ($clause_is_unique ? '' : ' LIMIT 1');
                $del_str = PMA_getIcon('b_drop.png', __('Delete'), true);
            } elseif ($is_display['del_lnk'] == 'kp') {
                // kill process case
                $_url_params = array('db' => $db, 'table' => $table, 'sql_query' => $url_sql_query, 'goto' => 'main.php');
                $lnk_goto = 'sql.php' . PMA_generate_common_url($_url_params, 'text');
                $_url_params = array('db' => 'mysql', 'sql_query' => 'KILL ' . $row[0], 'goto' => $lnk_goto);
                $del_url = 'sql.php' . PMA_generate_common_url($_url_params);
                $del_query = 'KILL ' . $row[0];
                $js_conf = 'KILL ' . $row[0];
                $del_str = PMA_getIcon('b_drop.png', __('Kill'), true);
            }
            // end if (1.2.2)
            // 1.3 Displays the links at left if required
            if ($GLOBALS['cfg']['ModifyDeleteAtLeft'] && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) {
                if (!isset($js_conf)) {
                    $js_conf = '';
                }
                echo PMA_generateCheckboxAndLinks('left', $del_url, $is_display, $row_no, $where_clause, $where_clause_html, $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf);
            }
            // end if (1.3)
        }
        // end if (1)
        // 2. Displays the rows' values
        for ($i = 0; $i < $fields_cnt; ++$i) {
            $meta = $fields_meta[$i];
            $not_null_class = $meta->not_null ? 'not_null' : '';
            $relation_class = isset($map[$meta->name]) ? 'relation' : '';
            $pointer = $i;
            $is_field_truncated = false;
            //If the previous column had blob data, we need to reset the class
            // to $inline_edit_class
            $class = 'data ' . $inline_edit_class . ' ' . $not_null_class . ' ' . $alternating_color_class . ' ' . $relation_class;
            //  See if this column should get highlight because it's used in the
            //  where-query.
            if (isset($highlight_columns) && (isset($highlight_columns[$meta->name]) || isset($highlight_columns[PMA_backquote($meta->name)]))) {
                $condition_field = true;
            } else {
                $condition_field = false;
            }
            if ($_SESSION['tmp_user_values']['disp_direction'] == 'vertical' && (!isset($GLOBALS['printview']) || $GLOBALS['printview'] != '1')) {
                // the row number corresponds to a data row, not HTML table row
                $class .= ' row_' . $row_no;
                if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
                    $class .= ' vpointer';
                }
                if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
                    $class .= ' vmarker';
                }
            }
            // end if
            // Wrap MIME-transformations. [MIME]
            $default_function = 'default_function';
            // default_function
            $transform_function = $default_function;
            $transform_options = array();
            if ($GLOBALS['cfgRelation']['mimework'] && $GLOBALS['cfg']['BrowseMIME']) {
                if (isset($GLOBALS['mime_map'][$meta->name]['mimetype']) && isset($GLOBALS['mime_map'][$meta->name]['transformation']) && !empty($GLOBALS['mime_map'][$meta->name]['transformation'])) {
                    $include_file = PMA_securePath($GLOBALS['mime_map'][$meta->name]['transformation']);
                    if (file_exists('./libraries/transformations/' . $include_file)) {
                        $transformfunction_name = str_replace('.inc.php', '', $GLOBALS['mime_map'][$meta->name]['transformation']);
                        require_once './libraries/transformations/' . $include_file;
                        if (function_exists('PMA_transformation_' . $transformfunction_name)) {
                            $transform_function = 'PMA_transformation_' . $transformfunction_name;
                            $transform_options = PMA_transformation_getOptions(isset($GLOBALS['mime_map'][$meta->name]['transformation_options']) ? $GLOBALS['mime_map'][$meta->name]['transformation_options'] : '');
                            $meta->mimetype = str_replace('_', '/', $GLOBALS['mime_map'][$meta->name]['mimetype']);
                        }
                    }
                    // end if file_exists
                }
                // end if transformation is set
            }
            // end if mime/transformation works.
            $_url_params = array('db' => $db, 'table' => $table, 'where_clause' => $where_clause, 'transform_key' => $meta->name);
            if (!empty($sql_query)) {
                $_url_params['sql_query'] = $url_sql_query;
            }
            $transform_options['wrapper_link'] = PMA_generate_common_url($_url_params);
            // n u m e r i c
            if ($meta->numeric == 1) {
                // if two fields have the same name (this is possible
                //       with self-join queries, for example), using $meta->name
                //       will show both fields NULL even if only one is NULL,
                //       so use the $pointer
                if (!isset($row[$i]) || is_null($row[$i])) {
                    $vertical_display['data'][$row_no][$i] = PMA_buildNullDisplay($class, $condition_field, $meta, 'align="right"');
                } elseif ($row[$i] != '') {
                    $nowrap = ' nowrap';
                    $where_comparison = ' = ' . $row[$i];
                    $vertical_display['data'][$row_no][$i] = '<td align="right"' . PMA_prepare_row_data($class, $condition_field, $analyzed_sql, $meta, $map, $row[$i], $transform_function, $default_function, $nowrap, $where_comparison, $transform_options, $is_field_truncated);
                } else {
                    $vertical_display['data'][$row_no][$i] = PMA_buildEmptyDisplay($class, $condition_field, $meta, 'align="right"');
                }
                //  b l o b
            } elseif (stristr($meta->type, 'BLOB')) {
                // PMA_mysql_fetch_fields returns BLOB in place of
                // TEXT fields type so we have to ensure it's really a BLOB
                $field_flags = PMA_DBI_field_flags($dt_result, $i);
                // remove 'inline_edit' from $class as we can't edit binary data.
                $class = str_replace('inline_edit', '', $class);
                if (stristr($field_flags, 'BINARY')) {
                    if (!isset($row[$i]) || is_null($row[$i])) {
                        $vertical_display['data'][$row_no][$i] = PMA_buildNullDisplay($class, $condition_field, $meta);
                    } else {
                        // for blobstreaming
                        // if valid BS reference exists
                        if (PMA_BS_IsPBMSReference($row[$i], $db)) {
                            $blobtext = PMA_BS_CreateReferenceLink($row[$i], $db);
                        } else {
                            $blobtext = PMA_handle_non_printable_contents('BLOB', isset($row[$i]) ? $row[$i] : '', $transform_function, $transform_options, $default_function, $meta, $_url_params);
                        }
                        $vertical_display['data'][$row_no][$i] = PMA_buildValueDisplay($class, $condition_field, $blobtext);
                        unset($blobtext);
                    }
                    // not binary:
                } else {
                    if (!isset($row[$i]) || is_null($row[$i])) {
                        $vertical_display['data'][$row_no][$i] = PMA_buildNullDisplay($class, $condition_field, $meta);
                    } elseif ($row[$i] != '') {
                        // if a transform function for blob is set, none of these replacements will be made
                        if (PMA_strlen($row[$i]) > $GLOBALS['cfg']['LimitChars'] && $_SESSION['tmp_user_values']['display_text'] == 'P') {
                            $row[$i] = PMA_substr($row[$i], 0, $GLOBALS['cfg']['LimitChars']) . '...';
                            $is_field_truncated = true;
                        }
                        // displays all space characters, 4 space
                        // characters for tabulations and <cr>/<lf>
                        $row[$i] = $default_function != $transform_function ? $transform_function($row[$i], $transform_options, $meta) : $default_function($row[$i], array(), $meta);
                        $vertical_display['data'][$row_no][$i] = PMA_buildValueDisplay($class, $condition_field, $row[$i]);
                    } else {
                        $vertical_display['data'][$row_no][$i] = PMA_buildEmptyDisplay($class, $condition_field, $meta);
                    }
                }
                // g e o m e t r y
            } elseif ($meta->type == 'geometry') {
                $geometry_text = PMA_handle_non_printable_contents('GEOMETRY', isset($row[$i]) ? $row[$i] : '', $transform_function, $transform_options, $default_function, $meta);
                // remove 'inline_edit' from $class as we can't edit geometry data.
                $class = str_replace('inline_edit', '', $class);
                $vertical_display['data'][$row_no][$i] = PMA_buildValueDisplay($class, $condition_field, $geometry_text);
                unset($geometry_text);
                // n o t   n u m e r i c   a n d   n o t   B L O B
            } else {
                if (!isset($row[$i]) || is_null($row[$i])) {
                    $vertical_display['data'][$row_no][$i] = PMA_buildNullDisplay($class, $condition_field, $meta);
                } elseif ($row[$i] != '') {
                    // support blanks in the key
                    $relation_id = $row[$i];
                    // Cut all fields to $GLOBALS['cfg']['LimitChars']
                    // (unless it's a link-type transformation)
                    if (PMA_strlen($row[$i]) > $GLOBALS['cfg']['LimitChars'] && $_SESSION['tmp_user_values']['display_text'] == 'P' && !strpos($transform_function, 'link') === true) {
                        $row[$i] = PMA_substr($row[$i], 0, $GLOBALS['cfg']['LimitChars']) . '...';
                        $is_field_truncated = true;
                    }
                    // displays special characters from binaries
                    $field_flags = PMA_DBI_field_flags($dt_result, $i);
                    $is_html = false;
                    if (isset($meta->_type) && $meta->_type === MYSQLI_TYPE_BIT) {
                        $row[$i] = PMA_printable_bit_value($row[$i], $meta->length);
                        // some results of PROCEDURE ANALYSE() are reported as
                        // being BINARY but they are quite readable,
                        // so don't treat them as BINARY
                    } elseif (stristr($field_flags, 'BINARY') && $meta->type == 'string' && !(isset($GLOBALS['is_analyse']) && $GLOBALS['is_analyse'])) {
                        if ($_SESSION['tmp_user_values']['display_binary']) {
                            // user asked to see the real contents of BINARY
                            // fields
                            if ($_SESSION['tmp_user_values']['display_binary_as_hex'] && PMA_contains_nonprintable_ascii($row[$i])) {
                                $row[$i] = bin2hex($row[$i]);
                            } else {
                                $row[$i] = htmlspecialchars(PMA_replace_binary_contents($row[$i]));
                            }
                        } else {
                            // we show the BINARY message and field's size
                            // (or maybe use a transformation)
                            $row[$i] = PMA_handle_non_printable_contents('BINARY', $row[$i], $transform_function, $transform_options, $default_function, $meta, $_url_params);
                            $is_html = true;
                        }
                    }
                    if ($is_html) {
                        $vertical_display['data'][$row_no][$i] = PMA_buildValueDisplay($class, $condition_field, $row[$i]);
                    } else {
                        // transform functions may enable no-wrapping:
                        $function_nowrap = $transform_function . '_nowrap';
                        $bool_nowrap = $default_function != $transform_function && function_exists($function_nowrap) ? $function_nowrap($transform_options) : false;
                        // do not wrap if date field type
                        $nowrap = preg_match('@DATE|TIME@i', $meta->type) || $bool_nowrap ? ' nowrap' : '';
                        $where_comparison = ' = \'' . PMA_sqlAddslashes($row[$i]) . '\'';
                        $vertical_display['data'][$row_no][$i] = '<td ' . PMA_prepare_row_data($class, $condition_field, $analyzed_sql, $meta, $map, $row[$i], $transform_function, $default_function, $nowrap, $where_comparison, $transform_options, $is_field_truncated);
                    }
                } else {
                    $vertical_display['data'][$row_no][$i] = PMA_buildEmptyDisplay($class, $condition_field, $meta);
                }
            }
            // output stored cell
            if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') {
                echo $vertical_display['data'][$row_no][$i];
            }
            if (isset($vertical_display['rowdata'][$i][$row_no])) {
                $vertical_display['rowdata'][$i][$row_no] .= $vertical_display['data'][$row_no][$i];
            } else {
                $vertical_display['rowdata'][$i][$row_no] = $vertical_display['data'][$row_no][$i];
            }
        }
        // end for (2)
        // 3. Displays the modify/delete links on the right if required
        if ($GLOBALS['cfg']['ModifyDeleteAtRight'] && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) {
            if (!isset($js_conf)) {
                $js_conf = '';
            }
            echo PMA_generateCheckboxAndLinks('right', $del_url, $is_display, $row_no, $where_clause, $where_clause_html, $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf);
        }
        // end if (3)
        if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') {
            ?>
</tr>
            <?php 
        }
        // end if
        // 4. Gather links of del_urls and edit_urls in an array for later
        //    output
        if (!isset($vertical_display['edit'][$row_no])) {
            $vertical_display['edit'][$row_no] = '';
            $vertical_display['copy'][$row_no] = '';
            $vertical_display['delete'][$row_no] = '';
            $vertical_display['row_delete'][$row_no] = '';
        }
        $vertical_class = ' row_' . $row_no;
        if ($GLOBALS['cfg']['BrowsePointerEnable'] == true) {
            $vertical_class .= ' vpointer';
        }
        if ($GLOBALS['cfg']['BrowseMarkerEnable'] == true) {
            $vertical_class .= ' vmarker';
        }
        if (!empty($del_url) && $is_display['del_lnk'] != 'kp') {
            $vertical_display['row_delete'][$row_no] .= PMA_generateCheckboxForMulti($del_url, $is_display, $row_no, $where_clause_html, $del_query, '[%_PMA_CHECKBOX_DIR_%]', $alternating_color_class . $vertical_class);
        } else {
            unset($vertical_display['row_delete'][$row_no]);
        }
        if (isset($edit_url)) {
            $vertical_display['edit'][$row_no] .= PMA_generateEditLink($edit_url, $alternating_color_class . ' ' . $edit_anchor_class . $vertical_class, $edit_str, $where_clause, $where_clause_html);
        } else {
            unset($vertical_display['edit'][$row_no]);
        }
        if (isset($copy_url)) {
            $vertical_display['copy'][$row_no] .= PMA_generateCopyLink($copy_url, $copy_str, $where_clause, $where_clause_html, $alternating_color_class . $vertical_class);
        } else {
            unset($vertical_display['copy'][$row_no]);
        }
        if (isset($del_url)) {
            if (!isset($js_conf)) {
                $js_conf = '';
            }
            $vertical_display['delete'][$row_no] .= PMA_generateDeleteLink($del_url, $del_str, $js_conf, $alternating_color_class . $vertical_class);
        } else {
            unset($vertical_display['delete'][$row_no]);
        }
        echo $_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped' ? "\n" : '';
        $row_no++;
    }
    // end while
    // this is needed by PMA_displayTable() to generate the proper param
    // in the multi-edit and multi-delete form
    return $clause_is_unique;
}