I ran into a peculiar situation with a PHP web application that went from working for several years without incident to suddenly resulting in timeouts and spiking the load on my server. Some investigation traced it back to a seemingly benign and obscure change to PHP’s rand()
implementation between 5.3.3 and 5.3.4.
To summarize several hundred lines of code: it gets a value from an array where the index is a random number between X and Y. X and Y are highly unpredictable by nature of the application. It keeps trying with different values until something is returned. Something like:
See it? If you don’t, you shouldn’t feel bad, I didn’t see it initially either.
Prior to PHP 5.3.4 mt_/rand
did not check if the max is greater than the min. This has changed as a result of bug 46587. That 4 line change made an impact.
Take this example code:
In PHP 5.3.3 you’d get:
$ PHP test.php right: 3 wrong: 4 $ PHP test.php right: 2 wrong: 5
Despite the incorrect order of max/min it actually worked just fine. It had done so at least since PHP 4.3 (circa 2003) as far as I’m aware.
In PHP 5.3.4:
$ PHP test.php right: 2 PHP Warning: mt_rand(): max(1) is smaller than min(5) in /test/test.php on line 4 wrong:
As a result, this while(){}
never terminated until the timeout was reached.
The solution is obviously trivial once you actually trace this bug back:
This resulted in several GB’s worth of warnings in my error log in a matter of hours. You can also see how it (the brown area) dropped off once the fix was deployed as measured by % of wall clock time:
It’s the little things sometimes that cause all the trouble.
1 reply on “PHP 5.3.4 Changes rand(), Filled My Error Log, Spikes Load”
Hi,
How can I fix the mt_rand and have a flip it code on this code layout:
function AddVertLines($im_image,$i_width,$i_height,$s_x_func,$i_color,
$a_text_area,$i_char_width,$i_spacing)
{
global $bCleanText;
$i_text_left = $a_text_area[0];
$i_text_top = $a_text_area[1];
$i_text_right = $a_text_area[2];
$i_text_bot = $a_text_area[3];
for (eval(‘$ii = ‘.$s_x_func.’;’) ; $ii = $i_text_left && $ii < $i_text_right)
{
$i_char_pos = $ii – $i_text_left;
if (((int) ($i_char_pos / $i_char_width)) % $i_spacing == 0)
$b_split = TRUE;
else
{
$i_start = mt_rand(0,$i_text_top);
$i_end = mt_rand($i_text_bot,$i_height-1);
}
}
if ($b_split)
{
imageline($im_image,$ii,min($i_text_top-2,$i_start),$ii,$i_text_top,$i_color);
imageline($im_image,$ii,$i_text_bot+2,$ii,max($i_text_bot+2,$i_end),$i_color);
}
else
imageline($im_image,$ii,$i_start,$ii,$i_end,$i_color);
}
}
function AddNoise($im_image,$i_width,$i_height,$i_color,$a_text_area)
{
global $bCleanText;
$i_text_left = $a_text_area[0] – 4;
$i_text_top = $a_text_area[1];
$i_text_right = $a_text_area[2];
$i_text_bot = $a_text_area[3] + 4;
$n_pixels = mt_rand(($i_width * $i_height) / 20,($i_width * $i_height) / 10);
for ($ii = 0 ; $ii = $i_text_left && $i_x_pos = $i_text_top && $i_y_pos <= $i_text_bot)
if (mt_rand(0,2) != 1)
continue;
imagesetpixel($im_image,$i_x_pos,$i_y_pos,$i_color);
}