WPDB: Sanity check that any strings being stored in the DB are not too long to store correctly.

git-svn-id: https://develop.svn.wordpress.org/trunk@32299 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Gary Pendergast 2015-04-27 14:02:45 +00:00
parent ca8d6fb60f
commit 45b0abbef1
3 changed files with 141 additions and 0 deletions

View File

@ -1946,11 +1946,20 @@ class wpdb {
*/
protected function process_fields( $table, $data, $format ) {
$data = $this->process_field_formats( $data, $format );
if ( false === $data ) {
return false;
}
$data = $this->process_field_charsets( $data, $table );
if ( false === $data ) {
return false;
}
$data = $this->process_field_lengths( $data, $table );
if ( false === $data ) {
return false;
}
$converted_data = $this->strip_invalid_text( $data );
if ( $data !== $converted_data ) {
@ -2031,6 +2040,40 @@ class wpdb {
return $data;
}
/**
* For string fields, record the maximum string length that field can safely save.
*
* @since 4.2.1
* @access protected
*
* @param array $data As it comes from the wpdb::process_field_charsets() method.
* @param string $table Table name.
* @return array|False The same array as $data with additional 'length' keys, or false if
* any of the values were too long for their corresponding field.
*/
protected function process_field_lengths( $data, $table ) {
foreach ( $data as $field => $value ) {
if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
// We can skip this field if we know it isn't a string.
// This checks %d/%f versus ! %s because it's sprintf() could take more.
$value['length'] = false;
} else {
$value['length'] = $this->get_col_length( $table, $field );
if ( is_wp_error( $value['length'] ) ) {
return false;
}
}
if ( false !== $value['length'] && strlen( $value['value'] ) > $value['length'] ) {
return false;
}
$data[ $field ] = $value;
}
return $data;
}
/**
* Retrieve one variable from the database.
*
@ -2361,6 +2404,77 @@ class wpdb {
return $charset;
}
/**
* Retrieve the maximum string length allowed in a given column.
*
* @since 4.2.1
* @access public
*
* @param string $table Table name.
* @param string $column Column name.
* @return mixed Max column length as an int. False if the column has no
* length. WP_Error object if there was an error.
*/
public function get_col_length( $table, $column ) {
$tablekey = strtolower( $table );
$columnkey = strtolower( $column );
// Skip this entirely if this isn't a MySQL database.
if ( false === $this->is_mysql ) {
return false;
}
if ( empty( $this->col_meta[ $tablekey ] ) ) {
// This primes column information for us.
$table_charset = $this->get_table_charset( $table );
if ( is_wp_error( $table_charset ) ) {
return $table_charset;
}
}
if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
return false;
}
$typeinfo = explode( '(', $this->col_meta[ $tablekey ][ $columnkey ]->Type );
$type = strtolower( $typeinfo[0] );
if ( ! empty( $typeinfo[1] ) ) {
$length = trim( $typeinfo[1], ')' );
} else {
$length = false;
}
switch( $type ) {
case 'binary':
case 'char':
case 'varbinary':
case 'varchar':
return $length;
break;
case 'tinyblob':
case 'tinytext':
return 255; // 2^8 - 1
break;
case 'blob':
case 'text':
return 65535; // 2^16 - 1
break;
case 'mediumblob':
case 'mediumtext':
return 16777215; // 2^24 - 1
break;
case 'longblob':
case 'longtext':
return 4294967295; // 2^32 - 1
break;
default:
return false;
}
return false;
}
/**
* Check if a string is ASCII.
*

View File

@ -112,4 +112,30 @@ class Tests_Comment extends WP_UnitTestCase {
unset( $_SERVER['REMOTE_ADDR'] );
}
}
public function test_comment_field_lengths() {
// `wp_new_comment()` checks REMOTE_ADDR, so we fake it to avoid PHP notices.
if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
$remote_addr = $_SERVER['REMOTE_ADDR'];
} else {
$_SERVER['REMOTE_ADDR'] = '';
}
$post_id = $this->factory->post->create();
$data = array(
'comment_post_ID' => $post_id,
'comment_author' => rand_str(),
'comment_author_url' => '',
'comment_author_email' => '',
'comment_type' => '',
'comment_content' => str_repeat( 'A', 65536 ),
'comment_date' => '2011-01-01 10:00:00',
'comment_date_gmt' => '2011-01-01 10:00:00',
);
$id = wp_new_comment( $data );
$this->assertFalse( $id );
}
}

View File

@ -747,6 +747,7 @@ class Tests_DB extends WP_UnitTestCase {
'format' => '%s',
'charset' => $expected_charset,
'ascii' => false,
'length' => $wpdb->get_col_length( $wpdb->posts, 'post_content' ),
)
);