ID:               49361
 Comment by:       code-it at mail dot ru
 Reported By:      code-it at mail dot ru
 Status:           Verified
 Bug Type:         Strings related
 Operating System: *
 PHP Version:      5.3.0
 New Comment:

sjoerd, your example looks very similar to what ive got in my real-life
script when i discovered the problem for the first time. but you missed
one thing


when you use "\n" to wrap strings, there is just a small piece of code
that does all the work in strings.c and the bug can be easy killed with
the patch i provided in my report. but when you try 2+ length strings
instead of "\n", another code works and it works incorrectly too


Previous Comments:
------------------------------------------------------------------------

[2009-08-27 16:45:03] sjo...@php.net

Thank you for your bug report.

Your report is too long and too hard to understand. However, I did the
best I could to make a simple script which reproduces the problem you
describe and is more like real-life usage of wordwrap.

<?php
$lines = array(
        "The quick brown fox just",
        "jumped over the lazy dog",
        "which laid on the ground"
);

$text = implode("\n", $lines);
$wrapped = wordwrap($text, 24);

echo "Expected:\n".$text."\n";
echo "Actual:\n".$wrapped."\n";
?>

Expected:
The quick brown fox just
jumped over the lazy dog
which laid on the ground
Actual:
The quick brown fox just
jumped over the lazy
dog
which laid on the
ground


------------------------------------------------------------------------

[2009-08-25 15:58:31] code-it at mail dot ru

Description:
------------
wordwrapping suppose that

wordwrap(wordwrap($s,$n,$d),$n,$d) is equal to wordwrap($s,$n,$d) and
yes, sometimes php works that way:

$s0 = 'a a a a a a a a';
$s1 = wordwrap($s0,7,'XX');
$s2 = wordwrap($s1,7,'XX');

gives $s1==$s2=='a a a aXXa a a a'


but if we add an extra space to the end of $s0, the result will be
'a a a aXXa a a aXX' != 'a a a aXXa a aXXaXX'


if we construct $s0 as (a )+a? we get $s1!=$s2 if and only if
strlen($s0)%8==0. more, the diff between $s1 and $s2 every time is the
same: trailing 'XXaXX' in $s2 instead of ' aXX' in $s1.


----------------------------

now lets take a look at the case of 1-char-length thing as the 3rd
argument to wordwrap


$s0 = 'a a a a a a a a a a a'; // as above, $s0 is constructed as (a
)+a?
$s1 = wordwrap($s0,5,'X');
$s2 = wordwrap($s1,5,'X');

here we only get $s1==$s2 having strlen($s0)<11!


this bug is related to line 828 in
/php-src/branches/PHP_5_3/ext/standard/string.c?revision=287264:

current line:   laststart = lastspace = current;
should be:              laststart = lastspace = current+1;

+1 is obviuos: if we found a breakchar in the string, we can forget
about everything to the left of it INCLUDING itself and restart the
whole algorythm at the NEXT character as the first character in our new
string. so the very first `laststart = lastspace = 0;` to start becomes
`laststart = lastspace = current+1;` to restart. this patch completely
removes the strange behaviour.



when strlen(3rd argument to wordwrap)>1 another section of code works
and the above patch doesnt affect it

Reproduce code:
---------------
<?
function f( $len, $breakstr, $n) {
        echo "\n-------- \$len=$len, \$breakstr='$breakstr', \$n=$n
-------\n";
        for ( $i=1, $c = 'a ', $s0='', $x=1, $k=0; $i<=$n; $i++) {
                $s0 .= $c[$x^=1];
                $s1 = wordwrap($s0,$len,$breakstr);
                $s2 = wordwrap($s1,$len,$breakstr);
                if ($s1==$s2) {
                        $k++;
                        continue;
                }
                echo "strlen(\$s0)=$i -> FAIL\n";
        }
        if ($k==$n) {
                echo "passed all, no fails\n";
        }
}
f(5,'X',20);
f(7,'XX',50);
?>

Expected result:
----------------
-------- $len=5, $breakstr='X', $n=20 -------
passed all, no fails

-------- $len=7, $breakstr='XX', $n=50 -------
passed all, no fails


Actual result:
--------------
-------- $len=5, $breakstr='X', $n=20 -------
strlen($s0)=11 -> FAIL
strlen($s0)=12 -> FAIL
strlen($s0)=13 -> FAIL
strlen($s0)=14 -> FAIL
strlen($s0)=15 -> FAIL
strlen($s0)=16 -> FAIL
strlen($s0)=17 -> FAIL
strlen($s0)=18 -> FAIL
strlen($s0)=19 -> FAIL
strlen($s0)=20 -> FAIL

-------- $len=7, $breakstr='XX', $n=50 -------
strlen($s0)=8 -> FAIL
strlen($s0)=16 -> FAIL
strlen($s0)=24 -> FAIL
strlen($s0)=32 -> FAIL
strlen($s0)=40 -> FAIL
strlen($s0)=48 -> FAIL



------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=49361&edit=1

Reply via email to