Home > Net >  Why substr() returning wrong result when used in a while loop PHP
Why substr() returning wrong result when used in a while loop PHP

Time:05-11

So im using substr to copy certain content inside a while loop but after the first iteration it always return wrong result i tried everything and im sure the logic is right but still im not getting what i want.

This is how it should work user will give me a text composed of many line each line got values and different values are separated by a pipe ( | ).

After separating values i have to get the bin and the short bin which is first 6 digits of the bin in first iteration im getting 6 digits, but in second im getting only 3,

When i tried adding a third line for a third iteration i got 4 digits this is my code

<?php
    
$text = "
    4535903705830785|Expirymonth|Expiryyear|CVV|DOB|SSN|FirstName|LastName|Address|ZipCode|City|State|NumPhone|Email|     
    4535903705830785|Expirymonth|Expiryyear|CVV|DOB|SSN|FirstName|LastName|Address|ZipCode|City|State|NumPhone|Email|
    ";
    
while(!empty($text)){
    $bin = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($bin) 1,strlen($text));
    $short_bin = substr($bin,0,6);
    echo $bin;
    echo '<br>';
    echo $short_bin;
    echo '<br>';
    
    $exp_month = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($exp_month) 1,strlen($text));
    echo $exp_month;
    echo '<br>';
    
    $exp_year = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($exp_year) 1,strlen($text));
    echo $exp_year;
    echo '<br>';
    
    $cvv = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($cvv) 1,strlen($text));
    echo $cvv;
    echo '<br>';
    
    $dob = substr($text, 0, strpos($text, "|"));
    $text = substr($text, strlen($dob)   1, strlen($text));
    echo $dob;
    echo '<br>';
    
    $ssn = substr($text, 0, strpos($text, "|"));
    $text = substr($text, strlen($ssn)   1, strlen($text));
    echo $ssn;
    echo '<br>';
    
    $firstname = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($firstname) 1,strlen($text));
    echo $firstname;
    echo '<br>';
    
    $lastname = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($lastname) 1,strlen($text));
    echo $lastname;
    echo '<br>';
    
    $address = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($address) 1,strlen($text));
    echo $address;
    echo '<br>';
    
    $zip_code = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($zip_code) 1,strlen($text));
    echo $zip_code;
    echo '<br>';
    
    $city = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($city) 1,strlen($text));
    echo $city;
    echo '<br>';
    
    $state = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($state) 1,strlen($text));
    echo $state;
    echo '<br>';
    
    $phone = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($phone) 1,strlen($text));
    echo $phone;
    echo '<br>';
    
    $email = substr($text,0,strpos($text,"|"));
    $text = substr($text,strlen($email) 1,strlen($text));
    echo $email;
    echo '<br>';
    echo '<br>';
    echo '<br>';
}
?>  

after running the code im getting this result enter image description here

CodePudding user response:

Your problem is that you're not accounting for all the characters in the string, so you've got spaces and newlines which you're not noticing because you're outputting HTML.

If you change echo $bin; and echo $short_bin; to var_dump($bin); and var_dump($short_bin); you'll see what I mean. Copying and pasting the code as given, and removing the rest of the output I got this:

string(17) "
4535903705830785"
string(6) "
45359"
string(22) "     
4535903705830785"
string(6) "     
"
string(0) ""
string(0) ""

On the first loop, I got a newline at the beginning of $bin, so $short_bin ended up with that newline plus 5 digits; on the second loop, I got 5 spaces and a newline, so those are all that ended up in $short_bin. Depending on the exact spacing, you'll get various different combinations.

If I add a call to trim after re-allocating $text but before extracting $short_bin, I get the expected result:

$bin = substr($text,0,strpos($text,"|"));
$text = substr($text,strlen($bin) 1,strlen($text));
$bin = trim($bin);
$short_bin = substr($bin,0,6);

However, the whole approach is over-complicated and error-prone based on the specification you've given, since you can just use two calls to explode - one to get the individual lines, and one to get the fields within a line. You can then trim each line as you see it, and skip any empty lines.

$text = "
4535903705830785|Expirymonth|Expiryyear|CVV|DOB|SSN|FirstName|LastName|Address|ZipCode|City|State|NumPhone|Email|     
4535903705830785|Expirymonth|Expiryyear|CVV|DOB|SSN|FirstName|LastName|Address|ZipCode|City|State|NumPhone|Email|
";

foreach ( explode("\n", $text) as $line ) {
    $line = trim($line);
    if ( empty($line) ) {
        continue;
    }
    
    [
        $bin, $exp_month, $exp_year, $cvv, 
        $dob, $ssn, $firstname, $lastname, 
        $address, $zip_code, $city, $state, 
        $phone, $email
    ] = explode('|', $line);
    $short_bin = substr($bin,0,6);
    
    var_dump(
        $bin, $exp_month, $exp_year, $cvv, 
        $dob, $ssn, $firstname, $lastname, 
        $address, $zip_code, $city, $state, 
        $phone, $email, $short_bin
    );
}

[Live Demo]

Note that this will probably be significantly faster on a large data set, because you won't be constantly re-allocating new strings as you remove parts from $text. A version using strpos could be faster still, if you had a huge data set where that mattered, but only if you made use of the $offset parameter to find "next |" or "next newline", and left $text unchanged; it would still be more error-prone, though, so I'd stick to explode unless you're sure you need something else.

  •  Tags:  
  • php
  • Related