Merge pull request #1189 from D-storm/FR-982

rfe-982: Support for editing binary fields in hexadecimal
This commit is contained in:
Isaac Bennetch 2014-05-21 12:52:02 -04:00
commit 02c4e352c5
16 changed files with 514 additions and 345 deletions

View File

@ -7,6 +7,7 @@ phpMyAdmin - ChangeLog
- rfe #1448 Allow clicking an approximate row count to get a correct one
- rfe #1487 "Browse foreign values" should be a modal dialog
- rfe #1523 Better visual clue for table structure primary key column
- rfe #982 Support for editing binary fields in hexadecimal
4.2.3.0 (not yet released)

View File

@ -1643,14 +1643,6 @@ Browse mode
descending order for columns of type TIME, DATE, DATETIME and
TIMESTAMP, ascending order else- by default.
.. config:option:: $cfg['DisplayBinaryAsHex']
:type: boolean
:default: true
Defines whether the "Show binary contents as HEX" browse option is
ticked by default.
.. config:option:: $cfg['GridEditing']
:type: string

View File

@ -641,12 +641,16 @@ function PMA_makegrid(t, enableResize, enableReorder, enableVisib, enableGridEdi
if (($this_field.attr('data-decimals') > 0) && ( $this_field.attr('data-type').indexOf('time') != -1)){
new_html = new_html.substring(0, new_html.length - (6 - $this_field.attr('data-decimals')));
}
if ($this_field.is('.truncated')) {
if (new_html.length > g.maxTruncatedLen) {
new_html = new_html.substring(0, g.maxTruncatedLen) + '...';
}
$this_field.removeClass('truncated');
if (PMA_commonParams.get('pftext') === 'P' && new_html.length > g.maxTruncatedLen) {
$this_field.addClass('truncated');
new_html = new_html.substring(0, g.maxTruncatedLen) + '...';
}
$this_field.find('span').text(new_html);
var selector = 'span';
if ($this_field.hasClass('hex') && $this_field.find('a').length) {
selector = 'a';
}
$this_field.find(selector).text(new_html);
}
if ($this_field.is('.bit')) {
$this_field.find('span').text($this_field.data('value'));
@ -954,11 +958,6 @@ function PMA_makegrid(t, enableResize, enableReorder, enableVisib, enableGridEdi
g.lastXHR = null;
$editArea.removeClass('edit_area_loading');
if (data.success === true) {
if ($td.is('.truncated')) {
// get the truncated data length
g.maxTruncatedLen = $(g.currentEditCell).text().length - 3;
}
$td.data('original_data', data.value);
$(g.cEdit).find('.edit_box').val(data.value);
$editArea.append('<textarea></textarea>');
@ -1150,6 +1149,8 @@ function PMA_makegrid(t, enableResize, enableReorder, enableVisib, enableGridEdi
} else {
if ($this_field.is('.bit')) {
fields_type.push('bit');
} else if ($this_field.hasClass('hex')) {
fields_type.push('hex');
}
fields_null.push('');
fields.push($this_field.data('value'));
@ -1366,6 +1367,14 @@ function PMA_makegrid(t, enableResize, enableReorder, enableVisib, enableGridEdi
// because selected value from drop-down, new window or multiple
// selection list will always be updated to the edit box
this_field_params[field_name] = $(g.cEdit).find('.edit_box').val();
} else if ($this_field.hasClass('hex')) {
if ($(g.cEdit).find('.edit_box').val().match(/^[a-f0-9]*$/i) !== null) {
this_field_params[field_name] = $(g.cEdit).find('.edit_box').val();
} else {
var hexError = '<div class="error">' + PMA_messages.strEnterValidHex + '</div>';
PMA_ajaxShowMessage(hexError, false);
this_field_params[field_name] = PMA_getCellValue(g.currentEditCell);
}
} else {
this_field_params[field_name] = $(g.cEdit).find('.edit_box').val();
}
@ -1660,6 +1669,7 @@ function PMA_makegrid(t, enableResize, enableReorder, enableVisib, enableGridEdi
// initialize cell editing configuration
g.saveCellsAtOnce = $('#save_cells_at_once').val();
g.maxTruncatedLen = PMA_commonParams.get('LimitChars');
// register events
$(t).find('td.data.click1')

View File

@ -352,6 +352,7 @@ $js_messages['strColVisibHint'] = __(
);
$js_messages['strShowAllCol'] = __('Show all');
$js_messages['strAlertNonUnique'] = __('This table does not contain a unique column. Features related to the grid edit, checkbox, Edit, Copy and Delete links may not work after saving.');
$js_messages['strEnterValidHex'] = __('Please enter valid hexadecimal string. Valid characters are 0-9, A-F.');
// this approach does not work when the parameter is changed via user prefs
switch ($GLOBALS['cfg']['GridEditing']) {

View File

@ -173,6 +173,10 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
// Unchecks the Ignore checkbox for the current row
$("input[name='insert_ignore_" + multi_edit + "']").prop('checked', false);
var $this_input = $("input[name='fields[multi_edit][" + multi_edit + "][" + urlField + "]']");
// check if it is textarea rather than input
if ($this_input.length === 0) {
$this_input = $("textarea[name='fields[multi_edit][" + multi_edit + "][" + urlField + "]']");
}
// Does this field come from datepicker?
if ($this_input.data('comes_from') == 'datepicker') {
@ -228,9 +232,17 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType)
return false;
}
}
// validate binary & blob types
if (theType.indexOf('blob') > -1 || theType.indexOf('binary') > -1) {
$this_input.removeClass("invalid_value");
if ($this_input.val().match(/^[a-f0-9]*$/i) === null) {
$this_input.addClass("invalid_value");
return false;
}
}
}
}
/* End of datetime validation*/
/* End of fields validation*/
/**

View File

@ -1661,11 +1661,6 @@ class PMA_DisplayResults
'display_blob', __('Show BLOB contents'),
! empty($_SESSION['tmpval']['display_blob']), false
)
. '<br />'
. PMA_Util::getCheckbox(
'display_binary_as_hex', __('Show binary contents as HEX'),
! empty($_SESSION['tmpval']['display_binary_as_hex']), false
)
. '</div>';
// I would have preferred to name this "display_transformation".
@ -2413,8 +2408,8 @@ class PMA_DisplayResults
*
* @access private
*
* @see _getDataCellForBlobColumns(), _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericAndNonBlobColumns()
* @see _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericColumns()
*/
private function _buildValueDisplay($class, $condition_field, $value)
{
@ -2435,9 +2430,9 @@ class PMA_DisplayResults
*
* @access private
*
* @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
* @see _getDataCellForNumericColumns(),
* _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericAndNonBlobColumns()
* _getDataCellForNonNumericColumns()
*/
private function _buildNullDisplay($class, $condition_field, $meta, $align = '')
{
@ -2463,9 +2458,9 @@ class PMA_DisplayResults
*
* @access private
*
* @see _getDataCellForNumericColumns(), _getDataCellForBlobColumns(),
* @see _getDataCellForNumericColumns(),
* _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericAndNonBlobColumns()
* _getDataCellForNonNumericColumns()
*/
private function _buildEmptyDisplay($class, $condition_field, $meta, $align = '')
{
@ -2517,6 +2512,11 @@ class PMA_DisplayResults
$bit_class = ' bit';
}
$hex_class = '';
if (strpos($meta->flags, 'binary') !== false) {
$hex_class = ' hex';
}
$mime_type_class = '';
if (isset($meta->mimetype)) {
$mime_type_class = ' ' . preg_replace('/\//', '_', $meta->mimetype);
@ -2525,7 +2525,7 @@ class PMA_DisplayResults
return $class . ($condition_field ? ' condition' : '') . $nowrap
. ' ' . ($is_field_truncated ? ' truncated' : '')
. ($transformation_plugin != $default_function ? ' transformed' : '')
. $enum_class . $set_class . $bit_class . $mime_type_class;
. $enum_class . $set_class . $bit_class . $hex_class . $mime_type_class;
} // end of the '_addClass()' function
@ -2962,20 +2962,6 @@ class PMA_DisplayResults
$transform_options
);
} elseif (stristr($meta->type, self::BLOB_FIELD)) {
// b l o b
// PMA_mysql_fetch_fields returns BLOB in place of
// TEXT fields type so we have to ensure it's really a BLOB
$field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $i);
$vertical_display['data'][$row_no][$i]
= $this->_getDataCellForBlobColumns(
$row[$i], $class, $meta, $_url_params, $field_flags,
$transformation_plugin, $default_function,
$transform_options, $condition_field, $is_field_truncated
);
} elseif ($meta->type == self::GEOMETRY_FIELD) {
// g e o m e t r y
@ -2992,10 +2978,10 @@ class PMA_DisplayResults
);
} else {
// n o t n u m e r i c a n d n o t B L O B
// n o t n u m e r i c
$vertical_display['data'][$row_no][$i]
= $this->_getDataCellForNonNumericAndNonBlobColumns(
= $this->_getDataCellForNonNumericColumns(
$row[$i], $class, $meta, $map, $_url_params,
$condition_field, $transformation_plugin,
$default_function, $transform_options,
@ -3717,105 +3703,6 @@ class PMA_DisplayResults
} // end of the '_getDataCellForNumericColumns()' function
/**
* Get data cell for blob type fields
*
* @param string $column the relevant column in data row
* @param string $class the html class for column
* @param object $meta the meta-information about this
* field
* @param array $_url_params the parameters for generate url
* @param string $field_flags field flags for column(blob,
* primary etc)
* @param string $transformation_plugin the name of transformation function
* @param string $default_function the default transformation function
* @param string $transform_options the transformation parameters
* @param boolean $condition_field the column should highlighted
* or not
* @param boolean $is_field_truncated the condition for blob data
* replacements
*
* @return string $cell the prepared cell, html content
*
* @access private
*
* @see _getTableBody()
*/
private function _getDataCellForBlobColumns(
$column, $class, $meta, $_url_params, $field_flags, $transformation_plugin,
$default_function, $transform_options, $condition_field, $is_field_truncated
) {
if (stristr($field_flags, self::BINARY_FIELD)) {
// remove 'grid_edit' from $class as we can't edit binary data.
$class = str_replace('grid_edit', '', $class);
if (! isset($column) || is_null($column)) {
$cell = $this->_buildNullDisplay($class, $condition_field, $meta);
} else {
$blobtext = $this->_handleNonPrintableContents(
self::BLOB_FIELD, (isset($column) ? $column : ''),
$transformation_plugin, $transform_options,
$default_function, $meta, $_url_params
);
$cell = $this->_buildValueDisplay(
$class, $condition_field, $blobtext
);
unset($blobtext);
}
} else {
// not binary:
if (! isset($column) || is_null($column)) {
$cell = $this->_buildNullDisplay($class, $condition_field, $meta);
} elseif ($column != '') {
// if a transform function for blob is set, none of these
// replacements will be made
$limitChars = $GLOBALS['cfg']['LimitChars'];
if (($GLOBALS['PMA_String']->strlen($column) > $limitChars)
&& ($_SESSION['tmpval']['pftext'] == self::DISPLAY_PARTIAL_TEXT)
&& empty($this->transformation_info[strtolower($this->__get('db'))][strtolower($this->__get('table'))][strtolower(strtolower($meta->name))])
) {
$column = $GLOBALS['PMA_String']->substr(
$column, 0, $GLOBALS['cfg']['LimitChars']
) . '...';
$is_field_truncated = true;
}
// displays all space characters, 4 space
// characters for tabulations and <cr>/<lf>
$column = ($default_function != $transformation_plugin)
? $transformation_plugin->applyTransformation(
$column,
$transform_options,
$meta
)
: $default_function($column, array(), $meta);
if ($is_field_truncated) {
$class .= ' truncated';
}
$cell = $this->_buildValueDisplay($class, $condition_field, $column);
} else {
$cell = $this->_buildEmptyDisplay($class, $condition_field, $meta);
}
}
return $cell;
} // end of the '_getDataCellForBlobColumns()' function
/**
* Get data cell for geometry type fields
*
@ -3843,9 +3730,6 @@ class PMA_DisplayResults
$is_field_truncated, $analyzed_sql
) {
$pftext = $_SESSION['tmpval']['pftext'];
$limitChars = $GLOBALS['cfg']['LimitChars'];
if (! isset($column) || is_null($column)) {
$cell = $this->_buildNullDisplay($class, $condition_field, $meta);
@ -3872,15 +3756,7 @@ class PMA_DisplayResults
// Convert to WKT format
$wktval = PMA_Util::asWKT($column);
if (($GLOBALS['PMA_String']->strlen($wktval) > $limitChars)
&& ($pftext == self::DISPLAY_PARTIAL_TEXT)
) {
$wktval = $GLOBALS['PMA_String']->substr(
$wktval, 0, $limitChars
) . '...';
$is_field_truncated = true;
}
$is_field_truncated = $this->_getPartialText($wktval);
$cell = $this->_getRowData(
$class, $condition_field, $analyzed_sql, $meta, $map,
@ -3896,16 +3772,8 @@ class PMA_DisplayResults
$where_comparison = ' = ' . $column;
$wkbval = $this->_displayBinaryAsPrintable($column, 'binary', 8);
if (($GLOBALS['PMA_String']->strlen($wkbval) > $limitChars)
&& ($pftext == self::DISPLAY_PARTIAL_TEXT)
) {
$wkbval = $GLOBALS['PMA_String']->substr(
$wkbval, 0, $GLOBALS['cfg']['LimitChars']
) . '...';
$is_field_truncated = true;
}
$wkbval = $GLOBALS['PMA_String']->substr(bin2hex($column), 8);
$is_field_truncated = $this->_getPartialText($wkbval);
$cell = $this->_getRowData(
$class, $condition_field,
@ -3937,7 +3805,7 @@ class PMA_DisplayResults
/**
* Get data cell for non numeric and non blob type fields
* Get data cell for non numeric type fields
*
* @param string $column the relevant column in data row
* @param string $class the html class for column
@ -3949,11 +3817,10 @@ class PMA_DisplayResults
* @param string $transformation_plugin the name of transformation function
* @param string $default_function the default transformation function
* @param string $transform_options the transformation parameters
* @param boolean $is_field_truncated the condition for blob data
* replacements
* @param boolean $is_field_truncated is data truncated due to LimitChars
* @param array $analyzed_sql the analyzed query
* @param integer &$dt_result the link id associated to the query
* which results have to be displayed
* which results have to be displayed
* @param integer $col_index the column index
*
* @return string $cell the prepared data cell, html content
@ -3962,18 +3829,26 @@ class PMA_DisplayResults
*
* @see _getTableBody()
*/
private function _getDataCellForNonNumericAndNonBlobColumns(
private function _getDataCellForNonNumericColumns(
$column, $class, $meta, $map, $_url_params, $condition_field,
$transformation_plugin, $default_function, $transform_options,
$is_field_truncated, $analyzed_sql, &$dt_result, $col_index
) {
$limitChars = $GLOBALS['cfg']['LimitChars'];
$is_analyse = $this->__get('is_analyse');
$field_flags = $GLOBALS['dbi']->fieldFlags($dt_result, $col_index);
if (stristr($field_flags, self::BINARY_FIELD)
&& ($GLOBALS['cfg']['ProtectBinary'] == 'all'
|| $GLOBALS['cfg']['ProtectBinary'] == 'noblob')
// disable inline grid editing
// if binary fields are protected
// or transformation plugin is of non text type
// such as image
if ((stristr($field_flags, self::BINARY_FIELD)
&& ($GLOBALS['cfg']['ProtectBinary'] === 'all'
|| ($GLOBALS['cfg']['ProtectBinary'] === 'noblob'
&& !stristr($meta->type, self::BLOB_FIELD))
|| ($GLOBALS['cfg']['ProtectBinary'] === 'blob'
&& stristr($meta->type, self::BLOB_FIELD))))
|| (gettype($transformation_plugin) === 'object'
&& strpos($transformation_plugin->getMIMEtype(), 'Text') === false)
) {
$class = str_replace('grid_edit', '', $class);
}
@ -3985,16 +3860,12 @@ class PMA_DisplayResults
} elseif ($column != '') {
// Cut all fields to $GLOBALS['cfg']['LimitChars']
// (unless it's a link-type transformation)
if ($GLOBALS['PMA_String']->strlen($column) > $limitChars
&& ($_SESSION['tmpval']['pftext'] == self::DISPLAY_PARTIAL_TEXT)
&& ! (gettype($transformation_plugin) == "object"
// (unless it's a link-type transformation or binary)
if (!(gettype($transformation_plugin) === "object"
&& strpos($transformation_plugin->getName(), 'Link') !== false)
&& !stristr($field_flags, self::BINARY_FIELD)
) {
$column = $GLOBALS['PMA_String']->substr(
$column, 0, $GLOBALS['cfg']['LimitChars']
) . '...';
$is_field_truncated = true;
$is_field_truncated = $this->_getPartialText($column);
}
$formatted = false;
@ -4008,26 +3879,31 @@ class PMA_DisplayResults
// being BINARY but they are quite readable,
// so don't treat them as BINARY
} elseif (stristr($field_flags, self::BINARY_FIELD)
&& ($meta->type == self::STRING_FIELD)
&& !(isset($is_analyse) && $is_analyse)
) {
if ($_SESSION['tmpval']['display_binary']) {
// user asked to see the real contents of BINARY
// fields
$column = $this->_displayBinaryAsPrintable($column, 'binary');
} else {
// we show the BINARY message and field's size
// (or maybe use a transformation)
$column = $this->_handleNonPrintableContents(
self::BINARY_FIELD, $column, $transformation_plugin,
$transform_options, $default_function,
$meta, $_url_params
);
$formatted = true;
// we show the BINARY or BLOB message and field's size
// (or maybe use a transformation)
$binary_or_blob = self::BLOB_FIELD;
if ($meta->type === self::STRING_FIELD) {
$binary_or_blob = self::BINARY_FIELD;
}
$column = $this->_handleNonPrintableContents(
$binary_or_blob, $column, $transformation_plugin,
$transform_options, $default_function,
$meta, $_url_params, $is_field_truncated
);
$class = $this->_addClass(
$class, $condition_field, $meta, '',
$is_field_truncated, $transformation_plugin, $default_function
);
$result = strip_tags($column);
// disable inline grid editing
// if binary or blob data is not shown
if (stristr($result, $binary_or_blob)) {
$class = str_replace('grid_edit', '', $class);
}
$formatted = true;
} elseif (((substr($meta->type, 0, 9) == self::TIMESTAMP_FIELD)
|| ($meta->type == self::DATETIME_FIELD)
|| ($meta->type == self::TIME_FIELD)
@ -4076,7 +3952,7 @@ class PMA_DisplayResults
return $cell;
} // end of the '_getDataCellForNonNumericAndNonBlobColumns()' function
} // end of the '_getDataCellForNonNumericColumns()' function
/**
@ -4443,23 +4319,6 @@ class PMA_DisplayResults
$query['display_binary'] = true;
}
if (isset($_REQUEST['display_binary_as_hex'])) {
$query['display_binary_as_hex'] = true;
unset($_REQUEST['display_binary_as_hex']);
} elseif (isset($_REQUEST['display_options_form'])) {
// we know that the checkbox was unchecked
unset($query['display_binary_as_hex']);
} elseif (isset($_REQUEST['full_text_button'])) {
// do nothing to keep the value that is there in the session
} else {
// display_binary_as_hex config option
if (isset($GLOBALS['cfg']['DisplayBinaryAsHex'])
&& ($GLOBALS['cfg']['DisplayBinaryAsHex'] === true)
) {
$query['display_binary_as_hex'] = true;
}
}
if (isset($_REQUEST['display_blob'])) {
$query['display_blob'] = true;
unset($_REQUEST['display_blob']);
@ -4498,9 +4357,6 @@ class PMA_DisplayResults
$_SESSION['tmpval']['display_binary'] = isset(
$query['display_binary']
);
$_SESSION['tmpval']['display_binary_as_hex'] = isset(
$query['display_binary_as_hex']
);
$_SESSION['tmpval']['display_blob'] = isset(
$query['display_blob']
);
@ -5501,31 +5357,32 @@ class PMA_DisplayResults
* Verifies what to do with non-printable contents (binary or BLOB)
* in Browse mode.
*
* @param string $category BLOB|BINARY|GEOMETRY
* @param string $content the binary content
* @param string $transformation_plugin transformation plugin.
* Can also be the default function:
* PMA_mimeDefaultFunction
* @param string $transform_options transformation parameters
* @param string $default_function default transformation function
* @param object $meta the meta-information about the field
* @param array $url_params parameters that should go to the
* download link
* @param string $category BLOB|BINARY|GEOMETRY
* @param string $content the binary content
* @param string $transformation_plugin transformation plugin.
* Can also be the default function:
* PMA_mimeDefaultFunction
* @param string $transform_options transformation parameters
* @param string $default_function default transformation function
* @param object $meta the meta-information about the field
* @param array $url_params parameters that should go to the
* download link
* @param boolean &$is_truncated the result is truncated or not
*
* @return mixed string or float
*
* @access private
*
* @see _getDataCellForBlobColumns(),
* _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericAndNonBlobColumns(),
* @see _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericColumns(),
* _getSortedColumnMessage()
*/
private function _handleNonPrintableContents(
$category, $content, $transformation_plugin, $transform_options,
$default_function, $meta, $url_params = array()
$default_function, $meta, $url_params = array(), &$is_truncated = null
) {
$is_truncated = false;
$result = '[' . $category;
if (isset($content)) {
@ -5544,11 +5401,13 @@ class PMA_DisplayResults
$result .= ']';
// if we want to use a text transformation on a BLOB column
if (gettype($transformation_plugin) == "object"
if (gettype($transformation_plugin) === "object"
&& (strpos($transformation_plugin->getMIMESubtype(), 'Octetstream')
|| strpos($transformation_plugin->getMIMEtype(), 'Text') !== false)
) {
$result = $content;
// Applying Transformations on hex string of binary data
// seems more appropriate
$result = bin2hex($content);
}
if ($size > 0) {
@ -5562,11 +5421,14 @@ class PMA_DisplayResults
} else {
$result = $default_function($result, array(), $meta);
if (stristr($meta->type, self::BLOB_FIELD)
&& $_SESSION['tmpval']['display_blob']
if (($_SESSION['tmpval']['display_binary']
&& $meta->type === self::STRING_FIELD)
|| ($_SESSION['tmpval']['display_blob']
&& stristr($meta->type, self::BLOB_FIELD))
) {
// in this case, restart from the original $content
$result = $this->_displayBinaryAsPrintable($content, 'blob');
$result = bin2hex($content);
$is_truncated = $this->_getPartialText($result);
}
/* Create link to download */
@ -5610,7 +5472,7 @@ class PMA_DisplayResults
* @access private
*
* @see _getDataCellForNumericColumns(), _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericAndNonBlobColumns(),
* _getDataCellForNonNumericColumns(),
*
*/
private function _getRowData(
@ -6060,50 +5922,34 @@ class PMA_DisplayResults
} // end of the '_getCheckboxAndLinks()' function
/**
* Display binary columns as hex string if requested
* otherwise escape the contents using the best possible way
* Truncates given string based on LimitChars configuration
* and Session pftext variable
* (string is truncated only if necessary)
*
* @param string $content String to parse
* @param string $binary_or_blob binary' or 'blob'
* @param int $hexlength optional, get substring
* @param string &$str string to be truncated
*
* @return String Displayable version of the binary string
* @return boolean true if truncated, otherwise false
*
* @access private
* @access private
*
* @see _getDataCellForGeometryColumns
* _getDataCellForNonNumericAndNonBlobColumns
* _handleNonPrintableContents
* @see _handleNonPrintableContents(), _getDataCellForGeometryColumns(),
* _getDataCellForNonNumericColumns
*/
private function _displayBinaryAsPrintable(
$content, $binary_or_blob, $hexlength = null
) {
if ($binary_or_blob === 'binary'
&& $_SESSION['tmpval']['display_binary_as_hex']
private function _getPartialText(&$str)
{
if ($GLOBALS['PMA_String']->strlen($str) > $GLOBALS['cfg']['LimitChars']
&& $_SESSION['tmpval']['pftext'] === self::DISPLAY_PARTIAL_TEXT
) {
$content = bin2hex($content);
if ($hexlength !== null) {
$content = $GLOBALS['PMA_String']->substr($content, $hexlength);
}
} elseif (PMA_Util::containsNonPrintableAscii($content)) {
if (PMA_PHP_INT_VERSION < 50400) {
$content = htmlspecialchars(
PMA_Util::replaceBinaryContents(
$content
)
);
} else {
// The ENT_SUBSTITUTE option is available for PHP >= 5.4.0
$content = htmlspecialchars(
PMA_Util::replaceBinaryContents(
$content
),
ENT_SUBSTITUTE
);
}
$str = $GLOBALS['PMA_String']->substr(
$str, 0, $GLOBALS['cfg']['LimitChars']
) . '...';
return true;
}
return $content;
return false;
}
}

View File

@ -206,6 +206,8 @@ class PMA_Header
{
$db = ! empty($GLOBALS['db']) ? $GLOBALS['db'] : '';
$table = ! empty($GLOBALS['table']) ? $GLOBALS['table'] : '';
$pftext = ! empty($_SESSION['tmpval']['pftext'])
? $_SESSION['tmpval']['pftext'] : '';
return array(
'common_query' => PMA_URL_getCommon('', '', '&'),
'opendb_url' => $GLOBALS['cfg']['DefaultTabDatabase'],
@ -226,6 +228,8 @@ class PMA_Header
'pma_text_left_default_tab' => PMA_Util::getTitleForTarget(
$GLOBALS['cfg']['NavigationTreeDefaultTabTable']
),
'LimitChars' => $GLOBALS['cfg']['LimitChars'],
'pftext' => $pftext,
'confirm' => $GLOBALS['cfg']['Confirm']
);
}

View File

@ -3683,11 +3683,6 @@ class PMA_Util
$default_function = $cfg['DefaultFunctions']['FUNC_UUID'];
}
// this is set only when appropriate and is always true
if (isset($field['display_binary_as_hex'])) {
$default_function = 'UNHEX';
}
return $default_function;
}

View File

@ -1090,13 +1090,6 @@ $cfg['MaxRows'] = 25;
*/
$cfg['Order'] = 'SMART';
/**
* default for 'Show binary contents as HEX'
*
* @global string $cfg['DisplayBinaryAsHex']
*/
$cfg['DisplayBinaryAsHex'] = true;
/**
* grid editing: save edited cell(s) in browse-mode at once
*

View File

@ -89,8 +89,6 @@ $strConfigDefaultTabTable_name = __('Default table tab');
$strConfigHideStructureActions_desc
= __('Whether the table structure actions should be hidden.');
$strConfigHideStructureActions_name = __('Hide table structure actions');
$strConfigDisplayBinaryAsHex_desc = __('Show binary contents as HEX by default.');
$strConfigDisplayBinaryAsHex_name = __('Show binary contents as HEX');
$strConfigDisplayServersList_desc
= __('Show server listing as a list instead of a drop down.');
$strConfigDisplayServersList_name = __('Display servers as a list');

View File

@ -112,7 +112,6 @@ $forms['Main_panel']['Browse'] = array(
'ShowAll',
'MaxRows',
'Order',
'DisplayBinaryAsHex',
'BrowsePointerEnable',
'BrowseMarkerEnable',
'GridEditing',

View File

@ -454,9 +454,12 @@ function PMA_getFunctionColumn($column, $is_upload, $column_name_appendix,
$tabindex, $idindex, $insert_mode
) {
$html_output = '';
if (($GLOBALS['cfg']['ProtectBinary'] && $column['is_blob'] && ! $is_upload)
|| ($GLOBALS['cfg']['ProtectBinary'] === 'all' && $column['is_binary'])
|| ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && ! $column['is_blob'])
if (($GLOBALS['cfg']['ProtectBinary'] === 'blob'
&& $column['is_blob'] && !$is_upload)
|| ($GLOBALS['cfg']['ProtectBinary'] === 'all'
&& $column['is_binary'])
|| ($GLOBALS['cfg']['ProtectBinary'] === 'noblob'
&& $column['is_binary'])
) {
$html_output .= '<td class="center">' . __('Binary') . '</td>' . "\n";
} elseif (strstr($column['True_Type'], 'enum')
@ -1095,6 +1098,11 @@ function PMA_getBinaryAndBlobColumn(
$vkey, $is_upload
) {
$html_output = '';
// Add field type : Protected or Hexadecimal
$fields_type_html = '<input type="hidden" name="fields_type'
. $column_name_appendix . '" value="%s" />';
// Default value : hex
$fields_type_val = 'hex';
if (($GLOBALS['cfg']['ProtectBinary'] === 'blob' && $column['is_blob'])
|| ($GLOBALS['cfg']['ProtectBinary'] === 'all')
|| ($GLOBALS['cfg']['ProtectBinary'] === 'noblob' && !$column['is_blob'])
@ -1107,9 +1115,8 @@ function PMA_getBinaryAndBlobColumn(
$html_output .= ' (' . $data_size[0] . ' ' . $data_size[1] . ')';
unset($data_size);
}
$html_output .= '<input type="hidden" name="fields_type'
. $column_name_appendix . '" value="protected" />'
. '<input type="hidden" name="fields'
$fields_type_val = 'protected';
$html_output .= '<input type="hidden" name="fields'
. $column_name_appendix . '" value="" />';
} elseif ($column['is_blob']
|| ($column['len'] > $GLOBALS['cfg']['LimitChars'])
@ -1127,6 +1134,7 @@ function PMA_getBinaryAndBlobColumn(
$unnullify_trigger, $tabindex, $tabindex_for_value, $idindex
);
}
$html_output .= sprintf($fields_type_html, $fields_type_val);
if ($is_upload && $column['is_blob']) {
$html_output .= '<br />'
@ -1680,21 +1688,11 @@ function PMA_getSpecialCharsAndBackupFieldForExistingRow(
} else {
// special binary "characters"
if ($column['is_binary']
|| ($column['is_blob'] && ! $GLOBALS['cfg']['ProtectBinary'])
|| ($column['is_blob'] && $GLOBALS['cfg']['ProtectBinary'] !== 'all')
) {
if ($_SESSION['tmpval']['display_binary_as_hex']
&& $GLOBALS['cfg']['ShowFunctionFields']
) {
$current_row[$column['Field']] = bin2hex(
$current_row[$column['Field']]
);
$column['display_binary_as_hex'] = true;
} else {
$current_row[$column['Field']] = bin2hex(
$current_row[$column['Field']]
= PMA_Util::replaceBinaryContents(
$current_row[$column['Field']]
);
}
);
} // end if
$special_chars = htmlspecialchars($current_row[$column['Field']]);
@ -1766,15 +1764,6 @@ function PMA_getSpecialCharsAndBackupFieldForInsertingMode(
}
$backup_field = '';
$special_chars_encoded = PMA_Util::duplicateFirstNewline($special_chars);
// this will select the UNHEX function while inserting
if (($column['is_binary']
|| ($column['is_blob'] && ! $GLOBALS['cfg']['ProtectBinary']))
&& (isset($_SESSION['tmpval']['display_binary_as_hex'])
&& $_SESSION['tmpval']['display_binary_as_hex'])
&& $GLOBALS['cfg']['ShowFunctionFields']
) {
$column['display_binary_as_hex'] = true;
}
return array(
$real_null_value, $data, $special_chars,
$backup_field, $special_chars_encoded
@ -2279,7 +2268,8 @@ function PMA_getQueryValuesForInsertAndUpdateInMultipleEdit($multi_edit_columns_
. ' = ' . $current_value_as_an_array;
} elseif (empty($multi_edit_funcs[$key])
&& isset($multi_edit_columns_prev[$key])
&& ("'" . PMA_Util::sqlAddSlashes($multi_edit_columns_prev[$key]) . "'" == $current_value)
&& (("'" . PMA_Util::sqlAddSlashes($multi_edit_columns_prev[$key]) . "'" === $current_value)
|| ('0x' . $multi_edit_columns_prev[$key] === $current_value))
) {
// No change for this column and no MySQL function is used -> next column
} elseif (! empty($current_value)) {
@ -2376,6 +2366,8 @@ function PMA_getCurrentValueForDifferentTypes($possibly_uploaded_val, $key,
} else {
$current_value = '';
}
} elseif ($type === 'hex') {
$current_value = '0x' . $current_value;
} elseif ($type == 'bit') {
$current_value = preg_replace('/[^01]/', '0', $current_value);
$current_value = "b'" . PMA_Util::sqlAddSlashes($current_value) . "'";

View File

@ -1755,6 +1755,10 @@ function PMA_sendQueryResponseForNoResultsReturned($analyzed_sql_results, $db,
function PMA_sendResponseForGridEdit($result)
{
$row = $GLOBALS['dbi']->fetchRow($result);
$field_flags = $GLOBALS['dbi']->fieldFlags($result, 0);
if (stristr($field_flags, PMA_DisplayResults::BINARY_FIELD)) {
$row[0] = bin2hex($row[0]);
}
$response = PMA_Response::getInstance();
$response->addJSON('value', $row[0]);
exit;

View File

@ -55,6 +55,7 @@ session_start();
// Standard environment for tests
$_SESSION[' PMA_token '] = 'token';
$_SESSION['tmpval']['pftext'] = 'F';
$GLOBALS['lang'] = 'en';
$GLOBALS['is_ajax_request'] = false;

View File

@ -16,6 +16,9 @@ require_once 'libraries/js_escape.lib.php';
require_once 'libraries/core.lib.php';
require_once 'libraries/Config.class.php';
require_once 'libraries/relation.lib.php';
require_once 'libraries/String.class.php';
require_once 'libraries/plugins/transformations/Text_Plain_Link.class.php';
require_once 'libraries/DatabaseInterface.class.php';
/**
* Test cases for displaying results.
@ -38,12 +41,22 @@ class PMA_DisplayResults_Test extends PHPUnit_Framework_TestCase
*/
protected function setUp()
{
$GLOBALS['server'] = 0;
$this->object = new PMA_DisplayResults('as', '', '', '');
$GLOBALS['PMA_Config'] = new PMA_Config();
$GLOBALS['PMA_Config']->enableBc();
$GLOBALS['server'] = 0;
$GLOBALS['text_dir'] = 'ltr';
$GLOBALS['PMA_String'] = new PMA_String();
include_once 'libraries/Response.class.php';
$dbi = $this->getMockBuilder('PMA_DatabaseInterface')
->disableOriginalConstructor()
->getMock();
$dbi->expects($this->any())->method('fieldFlags')
->will($this->returnArgument(1));
$GLOBALS['dbi'] = $dbi;
}
/**
@ -736,7 +749,10 @@ class PMA_DisplayResults_Test extends PHPUnit_Framework_TestCase
array(
'`a_sales`.`customer_id` ASC, `b_sales`.`customer_id` DESC',
array(
array('`a_sales`.`customer_id` ASC', '`b_sales`.`customer_id` DESC'),
array(
'`a_sales`.`customer_id` ASC',
'`b_sales`.`customer_id` DESC'
),
array('`a_sales`.`customer_id`', '`b_sales`.`customer_id`'),
array('ASC', 'DESC')
)
@ -1704,4 +1720,308 @@ class PMA_DisplayResults_Test extends PHPUnit_Framework_TestCase
$this->object->__get('highlight_columns')
);
}
/**
* Data provider for testGetPartialText
*
* @return array parameters and output
*/
public function dataProviderForTestGetPartialText()
{
return array(
array('P', 10, 'foo', false),
array('P', 1, 'foo', true),
array('F', 10, 'foo', false),
array('F', 1, 'foo', false)
);
}
/**
* Test _getPartialText
*
* @param string $pftext Partial or Full text
* @param integer $limitChars Partial or Full text
* @param string $str the string to be tested
* @param boolean $output return value of _getPartialText
*
* @return void
*
* @dataProvider dataProviderForTestGetPartialText
*/
public function testGetPartialText($pftext, $limitChars, $str, $output)
{
$_SESSION['tmpval']['pftext'] = $pftext;
$GLOBALS['cfg']['LimitChars'] = $limitChars;
$this->assertEquals(
$output,
$this->_callPrivateFunction(
'_getPartialText',
array(&$str)
)
);
}
/**
* Data provider for testHandleNonPrintableContents
*
* @return array parameters and output
*/
public function dataProviderForTestHandleNonPrintableContents()
{
$transformation_plugin = new Text_Plain_Link(null);
$meta = new StdClass();
$meta->type = 'BLOB';
$url_params = array('db' => 'foo');
return array(
array(
true,
true,
'BLOB',
'1001',
'PMA_mimeDefaultFunction',
'',
'PMA_mimeDefaultFunction',
$meta,
$url_params,
null,
'<a href="tbl_get_field.php?db=foo&amp;server=0&amp;lang=en'
. '&amp;token=token" class="disableAjax">31303031</a>'
),
array(
true,
false,
'BLOB',
'1001',
'PMA_mimeDefaultFunction',
'',
'PMA_mimeDefaultFunction',
$meta,
$url_params,
null,
'<a href="tbl_get_field.php?db=foo&amp;server=0&amp;lang=en'
. '&amp;token=token" class="disableAjax">[BLOB - 4 B]</a>'
),
array(
false,
false,
'BINARY',
'1001',
$transformation_plugin,
'',
'PMA_mimeDefaultFunction',
$meta,
$url_params,
null,
'<a href="31303031" title="" target="_new">31303031</a>'
),
array(
false,
true,
'GEOMETRY',
null,
'',
'',
'PMA_mimeDefaultFunction',
$meta,
$url_params,
null,
'[GEOMETRY - NULL]'
)
);
}
/**
* Test _handleNonPrintableContents
*
* @param boolean $display_binary show binary contents?
* @param boolean $display_blob show blob contents?
* @param string $category BLOB|BINARY|GEOMETRY
* @param string $content the binary content
* @param string $transformation_plugin transformation plugin.
* Can also be the default function:
* PMA_mimeDefaultFunction
* @param string $transform_options transformation parameters
* @param string $default_function default transformation function
* @param object $meta the meta-information about the field
* @param array $url_params parameters that should go to the
* download link
* @param boolean $is_truncated the result is truncated or not
* @param string $output the output of this function
*
* @return void
*
* @dataProvider dataProviderForTestHandleNonPrintableContents
*/
public function testHandleNonPrintableContents(
$display_binary, $display_blob, $category, $content,
$transformation_plugin, $transform_options, $default_function,
$meta, $url_params, $is_truncated, $output
) {
$_SESSION['tmpval']['display_binary'] = $display_binary;
$_SESSION['tmpval']['display_blob'] = $display_blob;
$GLOBALS['cfg']['LimitChars'] = 50;
$this->assertEquals(
$output,
$this->_callPrivateFunction(
'_handleNonPrintableContents',
array(
$category, $content, $transformation_plugin,
$transform_options, $default_function,
$meta, $url_params, &$is_truncated
)
)
);
}
/**
* Data provider for testGetDataCellForNonNumericColumns
*
* @return array parameters and output
*/
public function dataProviderForTestGetDataCellForNonNumericColumns()
{
$transformation_plugin = new Text_Plain_Link(null);
$meta = new StdClass();
$meta->type = 'BLOB';
$meta->flags = 'blob binary';
$meta2 = new StdClass();
$meta2->type = 'string';
$meta2->flags = '';
$meta2->decimals = 0;
$meta2->name = 'varchar';
$url_params = array('db' => 'foo');
return array(
array(
'all',
'1001',
'grid_edit',
$meta,
array(),
$url_params,
false,
'PMA_mimeDefaultFunction',
'PMA_mimeDefaultFunction',
array('http://www.github.com/'),
false,
array(),
0,
'binary',
'<td class="left hex"><a href="tbl_get_field.php?'
. 'db=foo&amp;server=0&amp;lang=en&amp;token=token" '
. 'class="disableAjax">[BLOB - 4 B]</a></td>'
),
array(
'noblob',
'1001',
'grid_edit',
$meta,
array(),
$url_params,
false,
$transformation_plugin,
'PMA_mimeDefaultFunction',
'',
false,
array(),
0,
'binary',
'<td class="left grid_edit transformed hex">'
. '<a href="31303031" title="" target="_new">31303031</a></td>'
),
array(
'noblob',
null,
'grid_edit',
$meta2,
array(),
$url_params,
false,
$transformation_plugin,
'PMA_mimeDefaultFunction',
'',
false,
array(),
0,
0,
'<td data-decimals="0" data-type="string" '
. 'class="grid_edit null"><i>NULL</i></td>'
),
array(
'all',
'foo bar baz',
'grid_edit',
$meta2,
array(),
$url_params,
false,
'PMA_mimeDefaultFunction',
'PMA_mimeDefaultFunction',
'',
false,
array(),
0,
0,
'<td data-decimals="0" data-type="string" '
. 'class="grid_edit ">foo bar baz</td>' . "\n"
)
);
}
/**
* Test _getDataCellForNonNumericColumns
*
* @param boolean $protectBinary all|blob|noblob|no
* @param string $column the relevant column in data row
* @param string $class the html class for column
* @param object $meta the meta-information about the field
* @param array $map the list of relations
* @param array $_url_params the parameters for generate url
* @param boolean $condition_field the column should highlighted
* or not
* @param string $transformation_plugin the name of transformation function
* @param string $default_function the default transformation function
* @param string $transform_options the transformation parameters
* @param boolean $is_field_truncated is data truncated due to LimitChars
* @param array $analyzed_sql the analyzed query
* @param integer $dt_result the link id associated to the query
* which results have to be displayed
* @param integer $col_index the column index
* @param string $output the output of this function
*
* @return void
*
* @dataProvider dataProviderForTestGetDataCellForNonNumericColumns
*/
public function testGetDataCellForNonNumericColumns(
$protectBinary, $column, $class, $meta, $map,
$_url_params, $condition_field, $transformation_plugin,
$default_function, $transform_options, $is_field_truncated,
$analyzed_sql, $dt_result, $col_index, $output
) {
$_SESSION['tmpval']['display_binary'] = true;
$_SESSION['tmpval']['display_blob'] = false;
$_SESSION['tmpval']['relational_display'] = false;
$GLOBALS['cfg']['LimitChars'] = 50;
$GLOBALS['cfg']['ProtectBinary'] = $protectBinary;
$this->assertEquals(
$output,
$this->_callPrivateFunction(
'_getDataCellForNonNumericColumns',
array(
$column, $class, $meta, $map, $_url_params, $condition_field,
$transformation_plugin, $default_function, $transform_options,
$is_field_truncated, $analyzed_sql, &$dt_result, $col_index
)
)
);
}
}

View File

@ -569,7 +569,7 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
*/
public function testGetFunctionColumn()
{
$GLOBALS['cfg']['ProtectBinary'] = true;
$GLOBALS['cfg']['ProtectBinary'] = 'blob';
$column['is_blob'] = true;
$this->assertTag(
PMA_getTagArray('<td class="center">', array('content' => 'Binary')),
@ -1141,8 +1141,9 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
);
$this->assertEquals(
'Binary - do not edit (5 B)<input type="hidden" name="fields_typeb" '
. 'value="protected" /><input type="hidden" name="fieldsb" value="" />'
'Binary - do not edit (5 B)<input type="hidden" '
. 'name="fieldsb" value="" /><input type="hidden" '
. 'name="fields_typeb" value="protected" />'
. '<br /><input type="file" name="fields_uploadfoo[123]" class="text'
. 'field" id="field_1_3" size="10" c/>&nbsp;(Max: 64KiB)' . "\n",
$result
@ -1158,9 +1159,9 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
);
$this->assertEquals(
'Binary - do not edit (4 B)<input type="hidden" name="fields_typeb" '
. 'value="protected" /><input type="hidden" name="fieldsb" value="" '
. '/>',
'Binary - do not edit (4 B)<input type="hidden" '
. 'name="fieldsb" value="" /><input type="hidden" '
. 'name="fields_typeb" value="protected" />',
$result
);
@ -1174,9 +1175,9 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
);
$this->assertEquals(
'Binary - do not edit (4 B)<input type="hidden" name="fields_typeb" '
. 'value="protected" /><input type="hidden" name="fieldsb" value="" '
. '/>',
'Binary - do not edit (4 B)<input type="hidden" '
. 'name="fieldsb" value="" /><input type="hidden" '
. 'name="fields_typeb" value="protected" />',
$result
);
@ -1200,7 +1201,8 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
"\na\n"
. '<textarea name="fieldsb" class="char" '
. 'maxlength="255" rows="5" cols="1" dir="/" '
. 'id="field_1_3" c tabindex="3"></textarea><br /><input type="file" '
. 'id="field_1_3" c tabindex="3"></textarea><input type="hidden" '
. 'name="fields_typeb" value="hex" /><br /><input type="file" '
. 'name="fields_uploadfoo[123]" class="textfield" id="field_1_3" '
. 'size="10" c/>&nbsp;(Max: 64KiB)' . "\n",
$result
@ -1224,7 +1226,8 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$this->assertEquals(
"\na\n"
. '<textarea name="fieldsb" class="" rows="20" cols="10" dir="/" '
. 'id="field_1_3" c tabindex="3"></textarea>',
. 'id="field_1_3" c tabindex="3"></textarea><input type="hidden" '
. 'name="fields_typeb" value="hex" />',
$result
);
@ -1248,7 +1251,8 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$this->assertEquals(
"\na\n"
. '<input type="text" name="fieldsb" value="" size="10" class='
. '"textfield" c tabindex="3" id="field_1_3" />',
. '"textfield" c tabindex="3" id="field_1_3" />'
. '<input type="hidden" name="fields_typeb" value="hex" />',
$result
);
}
@ -1732,7 +1736,6 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$current_row['f'] = "11001";
$extracted_columnspec['spec_in_brackets'] = 20;
$column['True_Type'] = 'char';
$_SESSION['tmpval']['display_binary_as_hex'] = true;
$GLOBALS['cfg']['ShowFunctionFields'] = true;
$result = PMA_getSpecialCharsAndBackupFieldForExistingRow(
@ -1750,9 +1753,8 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$result
);
// Case 5 (false display_binary_as_hex)
// Case 5
$current_row['f'] = "11001\x00";
$_SESSION['tmpval']['display_binary_as_hex'] = false;
$result = PMA_getSpecialCharsAndBackupFieldForExistingRow(
$current_row, $column, $extracted_columnspec, false, array('int'), 'a'
@ -1761,10 +1763,10 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$this->assertEquals(
array(
false,
'11001\0',
'11001\0',
'11001\0',
'<input type="hidden" name="fields_preva" value="11001\0" />'
"313130303100",
"313130303100",
"313130303100",
'<input type="hidden" name="fields_preva" value="313130303100" />'
),
$result
);
@ -1781,7 +1783,6 @@ class PMA_InsertEditTest extends PHPUnit_Framework_TestCase
$column['Default'] = b'101';
$column['is_binary'] = true;
$GLOBALS['cfg']['ProtectBinary'] = false;
$_SESSION['tmpval']['display_binary_as_hex'] = true;
$GLOBALS['cfg']['ShowFunctionFields'] = true;
$result = PMA_getSpecialCharsAndBackupFieldForInsertingMode($column, false);