Ticket #41925: 41925.patch
File 41925.patch, 5.7 KB (added by , 8 years ago) |
---|
-
src/wp-includes/wp-db.php
1248 1248 } 1249 1249 } 1250 1250 1251 $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it 1252 $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting 1253 $query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware 1254 $query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s 1255 $query = preg_replace( '/%(?:%|$|([^dsF]))/', '%%\\1', $query ); // escape any unescaped percents 1251 $query = preg_replace( '#[\'"]%(\d+\$)?s[\'"]#', '%$1s', $query ); // Remove mistakenly single/doublequoted placeholders 1252 1253 // Add single quotes around placeholders, but only for an odd number of leading % signs. 1254 // Force floats to be locale unaware, but only for an odd number of leading % signs. 1255 $query = preg_replace_callback( '#(%+)(\d+\$)?([fs])#', array( $this, '_normalize_prepare_placehoders' ), $query ); 1256 1256 1257 array_walk( $args, array( $this, 'escape_by_ref' ) ); 1257 1258 return @vsprintf( $query, $args ); 1258 1259 } 1259 1260 1260 1261 /** 1262 * Make sure the %f and %s placeholders are prepared correctly. 1263 * 1264 * Apply single quotes around an %s placeholder. 1265 * Make the %f placeholder locale-unaware. 1266 * 1267 * Make sure we only do this around the actual placeholder 1268 * disregarding any of the leading % signs where available. 1269 * 1270 * @since 4.8.2 1271 * @see wpdb::prepare 1272 * 1273 * @param array $matches The matches from within the replace callback above. 1274 * @return string 1275 */ 1276 public function _normalize_prepare_placehoders( $matches ) { 1277 // Just to make sure we received the needed stuff. 1278 if ( ! is_array( $matches ) || empty( $matches ) ) { 1279 return ''; 1280 } 1281 1282 $placeholder = $matches[0]; 1283 1284 // Return as is, not sure what to normalize here. 1285 if ( count( $matches ) < 3 ) { 1286 return $placeholder; 1287 } 1288 1289 // The number of leading % signs. 1290 $npercent = strlen( $matches[1] ); 1291 1292 // An even number of leading % signs renders the placeholder inert. 1293 if ( $npercent % 2 == 0 ) { 1294 return $placeholder; 1295 } 1296 1297 switch ( $matches[3] ) { 1298 case 'f': 1299 // Replace just the needed part. 1300 return str_replace( 'f', 'F', $placeholder ); 1301 case 's': 1302 // Quote just the needed part. 1303 return substr( $placeholder, 0, $npercent - 1 ) . "'" . substr( $placeholder, $npercent - 1 ) . "'"; 1304 default: 1305 return $placeholder; 1306 } 1307 } 1308 1309 /** 1261 1310 * First half of escaping for LIKE special characters % and _ before preparing for MySQL. 1262 1311 * 1263 1312 * Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security. -
tests/phpunit/tests/db.php
1118 1118 } 1119 1119 1120 1120 /** 1121 * 1121 * @ticket 41925 1122 1122 */ 1123 function test_prepare_with_ unescaped_percents() {1123 function test_prepare_with_numbered_parameters_and_leading_escapes() { 1124 1124 global $wpdb; 1125 1125 1126 $sql = $wpdb->prepare( '%d %1$d %%% %', 1 ); 1127 $this->assertEquals( '1 %1$d %% %', $sql ); 1126 $sql = $wpdb->prepare( '%1$d %%% % %%1$d%% %%%1$d%%', 1 ); 1127 $this->assertEquals( '1 %% %1$d% %1%', $sql ); 1128 1129 $sql = $wpdb->prepare( '%d %2$s', 1, 'hello' ); 1130 $this->assertEquals( "1 'hello'", $sql ); 1131 1132 $sql = $wpdb->prepare( "'%s'", 'hello' ); 1133 $this->assertEquals( "'hello'", $sql ); 1134 1135 $sql = $wpdb->prepare( '"%s"', 'hello' ); 1136 $this->assertEquals( "'hello'", $sql ); 1137 1138 $sql = $wpdb->prepare( "%s '%1\$s'", 'hello' ); 1139 $this->assertEquals( "'hello' 'hello'", $sql ); 1140 1141 $sql = $wpdb->prepare( "%s '%1\$s'", 'hello' ); 1142 $this->assertEquals( "'hello' 'hello'", $sql ); 1143 1144 $sql = $wpdb->prepare( '%s "%1$s"', 'hello' ); 1145 $this->assertEquals( "'hello' 'hello'", $sql ); 1146 1147 $sql = $wpdb->prepare( "%%s %%'%1\$s'", 'hello' ); 1148 $this->assertEquals( "%s %'hello'", $sql ); 1149 1150 $sql = $wpdb->prepare( '%%s %%"%1$s"', 'hello' ); 1151 $this->assertEquals( "%s %'hello'", $sql ); 1152 1153 $sql = $wpdb->prepare( '%%f %%"%1$f"', 3 ); 1154 $this->assertEquals( '%f %"3.000000"', $sql ); 1128 1155 } 1156 1157 function test_placeholder_normalization() { 1158 global $wpdb; 1159 1160 $prepare_pattern = '#(%+)(\d+\$)?([fs])#'; 1161 1162 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%s' ); 1163 $this->assertEquals( "'%s'", $sql ); 1164 1165 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%%s' ); 1166 $this->assertEquals( "%%s", $sql ); 1167 1168 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%%%s' ); 1169 $this->assertEquals( "%%'%s'", $sql ); 1170 1171 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%f' ); 1172 $this->assertEquals( '%F', $sql ); 1173 1174 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%%f' ); 1175 $this->assertEquals( '%%f', $sql ); 1176 1177 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%%%f' ); 1178 $this->assertEquals( '%%%F', $sql ); 1179 1180 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%%d' ); 1181 $this->assertEquals( '%%d', $sql ); 1182 1183 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), '%%%d' ); 1184 $this->assertEquals( '%%%d', $sql ); 1185 1186 $sql = preg_replace_callback( $prepare_pattern, array( $wpdb, '_normalize_prepare_placehoders' ), 'nothing to see here' ); 1187 $this->assertEquals( 'nothing to see here', $sql ); 1188 } 1129 1189 }