2013-07-10 28 views
12

strlen($str) đang trở lại giá trị âm cho một "chuỗi khổng lồ" được tạo bằng str_repeat:Tại sao PHP strlen() trả về độ dài âm?

<?php 

error_reporting(E_STRICT|E_ALL); 
echo phpversion(); // 5.3.26 
echo PHP_INT_MAX; // 9223372036854775807 
ini_set('memory_limit', '-1'); 
ini_set('max_execution_time', 0); 

$gb = 1024 * 1024 * 1024; 
$str = str_repeat('a', 2 * $gb); 
echo strlen($str); // gives int(-2147483648) 
echo $str[0]; // Notice: Uninitialized string offset: 0 

$str2 = str_repeat('a', 4 * $gb); 
echo strlen($str2); // gives int(0) 

$str3 = str_repeat('a', 123 + 4 * $gb); 
echo strlen($str3); // gives int(123) 

$str4 = str_repeat('a', 6 * $gb); // starts to wrap again... 
echo strlen($str4); // gives int(-2147483648) 
echo $str4[0]; // Notice: Uninitialized string offset: 0 

$str5 = str_repeat('a', 123 + 8 * $gb); 
echo strlen($str5); // gives int(123) 

?> 

là hành vi này được xác định?

Hoặc đây có phải là lỗi PHP không?

+0

Có vẻ như bạn đã chạy vào giá trị số nguyên tối đa trên 32 bit PHP. Một máy chủ 64bit sẽ báo cáo độ dài chính xác. – ceejayoz

+3

Khi strlen trả về một giá trị số nguyên, và tất cả các số nguyên trong PHP là các số nguyên đã ký, và PHP 32 bit sử dụng các số nguyên đã ký 32 bit, thì nó được định nghĩa ngầm định. PHP_INT_MAX không đổi cung cấp cho bạn giới hạn trên, trong đó giá trị "kết thúc tốt đẹp" và đi tiêu cực –

+0

Báo cáo PHP_INT_MAX của tôi 9223372036854775807 ... – Pacerier

Trả lời

5

string can be as large as 2GB.

Dường như thực tế là (2GB - 1). Này hoạt động tốt trên hộp x64 của tôi:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024 -1); 
echo $str[0]; 

... trong khi điều này phá vỡ:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024); 
echo $str[0]; 

gì bạn đang làm chỉ đơn giản là không xác định , và cuốn cẩm nang cần được sửa chữa. Tôi cũng đã mong đợi một cảnh báo.

Điều thú vị là, điều này đặt ra một lỗi nghiêm trọng:

$str = str_repeat('a', 2 * 1024 * 1024 * 1024 -2); // 2GB - 2 bytes 
$str .= 'b'; // ok 
$str .= 'c'; // PHP Fatal error: String size overflow 


Cập nhật:

Các bug report đã được tham dự vào. Tài liệu trên php.net đã được sửa và bây giờ viết "tối đa 2147483647 byte".

+1

Tôi theo đề xuất của bạn và gửi báo cáo lỗi: https://bugs.php.net/bug.php?id=65239 – Pacerier

+0

Vì lý do nào đó mặc dù 'echo $ str [0];' không hoạt động, chuỗi vẫn còn bộ nhớ và chúng ta có thể hoạt động trên nó (sử dụng trim vv). – Pacerier

+0

@Pacerier Bạn có thể muốn thêm trường hợp thử nghiệm với chuỗi nối vào báo cáo lỗi của bạn, có vẻ như để hỗ trợ ý tưởng rằng đây là lỗi tài liệu. Bên cạnh đó 'str_repeat' có lẽ nên ném cùng một lỗi nghiêm trọng như khi ghép nối. – RandomSeed

2

Tôi cho rằng bạn chỉ đơn giản là tràn một int với chuỗi lớn của bạn. Từ hướng dẫn sử dụng:

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.

Vì vậy, sẽ ổn nếu kích thước chuỗi của bạn có thể vừa với int.

+1

Không có tràn số nguyên, báo cáo PHP_INT_MAX của tôi 9223372036854775807 – Pacerier

+1

Đọc [hướng dẫn sử dụng cho chuỗi] (http://php.net/language.types.string). Không quan trọng giá trị số nguyên tối đa là gì nếu chuỗi có giới hạn khác. – Gumbo

+0

@Gumbo, strlen() trả về một int. Vì vậy, bạn bị ràng buộc để int giới hạn trong những gì bạn có thể trở về từ strlen. Nó không quan trọng những gì chuỗi giới hạn có. – Jk1

Các vấn đề liên quan