1

Can someone tell me if there's a better way doing this?

  • I am trying to generate a Serial number (function Taken from a Post on this site )
  • Check in my database if this Serial exist, if it does,regenerate another
  • Insert Unique serial into Db

    function GenerateSerial() {
    $chars = array(0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
    $sn = '';
    $max = count($chars)-1;
    for($i=0;$i<20;$i++){
     $sn .= (!($i % 5) && $i ? '-' : '').$chars[rand(0, $max)];
      }
    return $sn;
     }
    
    
     // Generate SN
    $serial =  GenerateSerial() ;
    
    
    // Check if it exists, then re-generate
    
     function checkifSerialexist () {
    
     $statement = $dbh->prepare("SELECT `id` FROM `table` WHERE `SN` = :existSN");
     $statement->bindParam(':existSN',  $serial, PDO::PARAM_STR); 
     $statement->execute();
     $statement->setFetchMode(PDO::FETCH_ASSOC);
     $result = $statement->fetchAll();
     $serial_count = $statement->rowCount();
    
     if ($serial_count > 0) {
    
     $serial =  GenerateSerial() ;
    
    } 
    
    
     return $serial ;   
    
    }
    
    
    //Now insert unique SN
    
    $stmt = $dbh->prepare("INSERT INTO `table` (SN) VALUES (:sn)");
    
    $stmt->bindParam(':sn', $serial, PDO::PARAM_STR);
    
    ect....
    
Awena
  • 1,002
  • 5
  • 20
  • 43
  • 1
    Just saying it "doesn't work" doesn't help us help you figure out what the problem is. Update your question to tell us if you're getting a syntax error or unexpected output or anything else that'd help us help you narrow down the problem. – Amal Murali Mar 12 '14 at 15:33
  • As a rule of thumb, you're better off just inserting the first generated value, and trapping the error that results from trying to insert a duplicate value. Checking first requires two round-trips to the dbms, and you *must* trap errors anyway. – Mike Sherrill 'Cat Recall' Mar 12 '14 at 15:41
  • 1
    Firing random strings at the database is not a good approach, it's not scalable. The more serials you have in the DB the more likely you are to generate an existing one again, and the worse your script will perform. Also race conditions could lead to the same serial being generated and inserted twice if yo udon't have a unique constraint in place. Why not just use autoincrement/sequences in the DB? Serial numbers imply being serial after all. – GordonM Mar 12 '14 at 15:42
  • @GordonM Agreed, and if you need something fancy-looking for the client, you can always use a hashing function on the autoincrement ID, I don't think that's going to hit a duplicate for the first few billion rows. – jeroen Mar 12 '14 at 15:50
  • @GordonM, or at least use a v4 GUID: http://stackoverflow.com/a/2117523/386178 (JavaScript solution). PHP COM extension includes `com_create_guid` – Brian S Mar 12 '14 at 15:58

5 Answers5

1

You are not calling your checkifSerialexist() function nor are you sending the serial (and the database connection...) as a parameter.

It should be something like:

$serial = GenerateSerial() ;

while (checkifSerialexist($dbh, $serial))
{
   $serial = GenerateSerial() ;
}

function checkifSerialexist ($dbh, $serial)
{
  $statement = $dbh->prepare("SELECT `id` FROM `table` WHERE `SN` = :existSN");
  $statement->bindParam(':existSN',  $serial, PDO::PARAM_STR); 
  $statement->execute();
  $statement->setFetchMode(PDO::FETCH_ASSOC);
  $result = $statement->fetchAll();

  return (count($result) > 0);   
}
jeroen
  • 91,079
  • 21
  • 114
  • 132
1

it's hard to say with the provided code, but my usual logic for unique generation is as follows:

$serial = genSerial();
while(!serialUnique($serial)) {
  $serial = genSerial();
}
save($serial);

i always make my check functions (e.g. serialUnique) return a boolean.

xero
  • 4,077
  • 22
  • 39
1

It seems like your function that checks if the serial exists does not have the serial you generated earlier.

Depending on where your function is, it might not have access to the variable. Pass it as a parameter and return true or false from the checkIfSerialExists function.

 function checkifSerialexist ($serial) {

 $statement = $dbh->prepare("SELECT `id` FROM `table` WHERE `SN` = :existSN");
 $statement->bindParam(':existSN',  $serial, PDO::PARAM_STR); 
 $statement->execute();
 $statement->setFetchMode(PDO::FETCH_ASSOC);
 $result = $statement->fetchAll();
 $serial_count = $statement->rowCount();

 if ($serial_count > 0) {
   return true;
 } else {
   return false;
 }   

}

Then from where you want to add it to the database, do something like

$serial =  GenerateSerial() ;
if(checkifSerialexist($serial)) {
  //Now insert unique SN

  $stmt = $dbh->prepare("INSERT INTO `table` (SN) VALUES (:sn)");

  $stmt->bindParam(':sn', $serial, PDO::PARAM_STR);

  //ect....

}
Matthias S
  • 3,358
  • 3
  • 21
  • 31
1
echo implode('-', str_split(substr(strtoupper(md5(microtime().rand(1000, 9999))), 0, 20), 5));
Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
Gabriel Glauber
  • 961
  • 11
  • 9
0

this is just the simply way, you can apply more secure if you need, you can use sha1(), microtime() combined with anothers functions and unique user data, and check if serial generated exsists in your data base... litle bit more secure, like:

$user_mail = 'customer@domain.com';

function salt($leng = 22) {
    return substr(sha1(mt_rand()), 0, $leng);  
}

function serial(){
    $hash = md5($user_mail . salt());

    for ($i = 0; $i < 1000; $i++) {
        $hash = md5($hash);
    }

    return implode('-', str_split(substr(strtoupper($hash), 0, 20), 5))
}

This exit: XXXX-XXXX-XXXX-XXXX serial pattern

Gabriel Glauber
  • 961
  • 11
  • 9