Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[PHP] Uniek 9-cijferig nummer genereren*

Pagina: 1
Acties:
  • 1.211 views

  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
Allen,

Ik gebruik de volgende code om een random 9 cijferige code te genereren:
PHP:
1
$code = substr(str_shuffle(str_repeat('123456789',9)),0,9);


Nu wordt deze code verderop in mijn script opgeslagen in de database. Het veld in de database is al unique constraint waardoor er sowieso nooit een duplicate entry voor kan komen. Echter moet dit al in het script opgelost worden zodat het script nog wel verder wordt uitgevoerd(krijgt nu een DIE).

Hoe kan ik dit in PHP oplossen. Sowieso door eerst de gegenereerde code in de database te controleren maar hoe kan ik hier een loop van maken dat hij vervolgens weer een nieuw nummer gaat genereren en als deze ook voorkomt weer een nieuwe net zo lang totdat er geen match meer is in de database.

Thanks!

  • Wiethoofd
  • Registratie: Juli 2007
  • Laatst online: 17-11 00:47

Wiethoofd

Broadcast TOM

Maak van het code genereren een (recursieve) functie, dan kan je makkelijker herhaaldelijk een code genereren.

Alle codes uit de database halen en in een array zetten en dan met in_array($nieuwe_code, $alle_codes) kijken of ie al eens gegenereerd is.

Volg me op Twitter/X & Bluesky


  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
Wiethoofd schreef op zaterdag 07 januari 2012 @ 21:35:
Maak van het code genereren een (recursieve) functie, dan kan je makkelijker herhaaldelijk een code genereren.

Alle codes uit de database halen en in een array zetten en dan met in_array($nieuwe_code, $alle_codes) kijken of ie al eens gegenereerd is.
Thanks voor je snelle reply. Alle code uit de database halen lijkt me een beetje overbodig want ik kan toch ook gewoon checken of die een match terugkrijgt als ik ga checken op de zojuist gegenereerde code.. Is er echt geen andere mogelijkheid?

  • mrc4nl
  • Registratie: September 2010
  • Laatst online: 11:17

mrc4nl

Procrastinatie expert

ik ben geen pro met php ,maar kun je niet gewoon 9x functie rand(1, 9) aanroepen, en zo in elkaar knutselen dat de getallen achter elkaar worden geplakt?

ora et labora


  • BtM909
  • Registratie: Juni 2000
  • Niet online

BtM909

Watch out Guys...

Wat wil je met die unieke code in je PHP sessie doen (voordat het wordt opgeslagen in de db)?

Ace of Base vs Charli XCX - All That She Boom Claps (RMT) | Clean Bandit vs Galantis - I'd Rather Be You (RMT)
You've moved up on my notch-list. You have 1 notch
I have a black belt in Kung Flu.


  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
mrc4nl schreef op zaterdag 07 januari 2012 @ 21:39:
ik ben geen pro met php ,maar kun je niet gewoon 9x functie rand(1, 9) aanroepen, en zo in elkaar knutselen dat de getallen achter elkaar worden geplakt?
Thanks! Maar theoretisch gezien zou dat alsnog een waarde op kunnen leveren die al in de database voorkomt. De kans is klein maar wel aanwezig. Het hoeft ook niet uitgesloten te worden echter wil ik wel dat hij gewoon als de code voorkomt in de database een nieuwe genereert

  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
BtM909 schreef op zaterdag 07 januari 2012 @ 21:40:
Wat wil je met die unieke code in je PHP sessie doen (voordat het wordt opgeslagen in de db)?
Een barcode genereren daar wordt het nu voor gebruikt. Het dient als een ticketnummer op een kaartje.

EDIT: Ik heb het hele script dus al gemaakt en alles draait om die unieke code. Zo wordt deze code ook naar gebruikers toegemailed in een PDF gestopt etc etc. Vandaar dat ik dit in PHP wil oplossen.

[ Voor 24% gewijzigd door Snors op 07-01-2012 21:43 ]


  • X_lawl_X
  • Registratie: September 2009
  • Laatst online: 17:22
Gewoon een SELECT op je database uitvoeren en zo de gegevens ophalen welke met je zojuist gegenereerde ID overeenkomt. Als er geen resultaten zijn dan inserten, anders opnieuw proberen. Ik denk dat dat de beste methode is.

  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
X_lawl_X schreef op zaterdag 07 januari 2012 @ 21:43:
Gewoon een SELECT op je database uitvoeren en zo de gegevens ophalen welke met je zojuist gegenereerde ID overeenkomt. Als er geen resultaten zijn dan inserten, anders opnieuw proberen. Ik denk dat dat de beste methode is.
Ja daar zat ik dus ook aan te denken. Echter vraag ik me dus af hoe ik zoiets kan maken. SELECT etc lukt me wel een if / else ook maar stel voor dat hij bij de 2de keer ook een code genereert die al voorkomt in de database. Hoe kan ik dus een loop maken die eindeloos doorgaat totdat die niks meer tegenkomt en hem dan insert.

  • Firesphere
  • Registratie: September 2010
  • Laatst online: 24-11 23:34

Firesphere

Yoshis before Hoshis

M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:39:
[...]

Thanks voor je snelle reply. Alle code uit de database halen lijkt me een beetje overbodig want ik kan toch ook gewoon checken of die een match terugkrijgt als ik ga checken op de zojuist gegenereerde code.. Is er echt geen andere mogelijkheid?
Theorie, ja, klopt. Maar dat kan je, in het geval van een database met een paar honderd/duizend records, nogal wat queries opleveren.

Terwijl wat Wiethoofd advieseerd, 1x de database aanspreken en dan het resultaat checken, veel minder belasting is voor je host.

Kwestie van efficientie. 1x de hele zooi ophalen zonder restrictie, of voor elke optie checken....

Enige wat mis kan gaan is als mensen exact tegelijk hetzelfde nummer krijgen. Die kans is echt heel klein.

Wat je als beveiliging zou kunnen doen, is voordat je definitief de data wegschrijft, nog een keer de check uitvoeren maar dan met een enkele fetch. Daarmee heb je 99% veilig een unieke code gegeven.

Iets met
if($fetch = 'haal-data-op-waar-unique = $unique){
probeer opnieuw;
}
else{
schrijf data weg
}

de read/write tijd van een sql query is klein genoeg om die unieke kans van exact tegelijk te voorkomen.

[ Voor 4% gewijzigd door Firesphere op 07-01-2012 21:47 ]

I'm not a complete idiot. Some parts are missing.
.Gertjan.: Ik ben een zelfstandige alcoholist, dus ik bepaal zelf wel wanneer ik aan het bier ga!


  • X_lawl_X
  • Registratie: September 2009
  • Laatst online: 17:22
M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:45:
Ja daar zat ik dus ook aan te denken. Echter vraag ik me dus af hoe ik zoiets kan maken. SELECT etc lukt me wel een if / else ook maar stel voor dat hij bij de 2de keer ook een code genereert die al voorkomt in de database. Hoe kan ik dus een loop maken die eindeloos doorgaat totdat die niks meer tegenkomt en hem dan insert.
PHP:
1
2
3
4
5
6
do
{
    $code = /* hier iets genereren */
    $query = mysql_query('SELECT code FROM veld WHERE code = ' . $code);    
    
} while (mysql_num_rows($query) != 0)


Niet getest, maar zoiets zal moeten werken.

  • Wiethoofd
  • Registratie: Juli 2007
  • Laatst online: 17-11 00:47

Wiethoofd

Broadcast TOM

M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:39:
Alle code uit de database halen lijkt me een beetje overbodig want ik kan toch ook gewoon checken of die een match terugkrijgt als ik ga checken op de zojuist gegenereerde code..
Alles in 1x uit de database halen ipv elke keer dat er een code gegenereerd wordt moeten matchen en bij een al voorkomende opnieuw moeten genereren en opnieuw in de database moeten kijken of hij al bestaat gaat bij veel codes steeds een select/query op je database uitvoeren. (wat Firesphere dus zegt)

M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:45:
maar stel voor dat hij bij de 2de keer ook een code genereert die al voorkomt in de database. Hoe kan ik dus een loop maken die eindeloos doorgaat totdat die niks meer tegenkomt en hem dan insert.
while loopje?

Volg me op Twitter/X & Bluesky


Verwijderd

Cel in je database aanmaken en deze auto increase geven en laten beginnen bij 10000000 ?

  • mrc4nl
  • Registratie: September 2010
  • Laatst online: 11:17

mrc4nl

Procrastinatie expert

M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:40:
[...]

Thanks! Maar theoretisch gezien zou dat alsnog een waarde op kunnen leveren die al in de database voorkomt. De kans is klein maar wel aanwezig. Het hoeft ook niet uitgesloten te worden echter wil ik wel dat hij gewoon als de code voorkomt in de database een nieuwe genereert
hoe dan ook je kan niet iets random maken en in de database gooien zonder kans op dezelfde waarde
(met kans van op 1:1miljoen)

je zal hoedan ook met sql query's aan de slag moeten om op aanwezigheid te cheken, en indien niet gevonden in te vullen.
wat x_lawl_x, dus zegt.
Verwijderd schreef op zaterdag 07 januari 2012 @ 21:47:
Cel in je database aanmaken en deze auto increase geven en laten beginnen bij 10000000 ?
nee het gaat om tickets en dat die niet te vervalsen zijn.
als het een linear verband is kun je ze makelijk namaken. (je weet het volgende nummer)
als je een random nummer op je kaartje hebt moet ie worden gecontroleerd met database en als ie erin staat weet je dat het kaartje geldig is

[ Voor 26% gewijzigd door mrc4nl op 07-01-2012 21:50 ]

ora et labora


  • Bee.nl
  • Registratie: November 2002
  • Niet online

Bee.nl

zoemt

M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:45:
[...]

Ja daar zat ik dus ook aan te denken. Echter vraag ik me dus af hoe ik zoiets kan maken. SELECT etc lukt me wel een if / else ook maar stel voor dat hij bij de 2de keer ook een code genereert die al voorkomt in de database. Hoe kan ik dus een loop maken die eindeloos doorgaat totdat die niks meer tegenkomt en hem dan insert.
En als je de code in een simpele do-while() stopt? Volgens mij zoek je een dergelijke constructie.
PHP:
1
2
3
4
5
6
7
do {
// 1) genereer id
// 2) controleer of het id al bestaat
// 3a) zo ja: zet conditie op true 
// 3b) zo nee: zet conditie op false
} while (conditie)
// werk verder met het id

[ Voor 0% gewijzigd door Bee.nl op 07-01-2012 21:53 . Reden: conditie omgedraaid ]


  • Firesphere
  • Registratie: September 2010
  • Laatst online: 24-11 23:34

Firesphere

Yoshis before Hoshis

Code die ik zelf ooit heb gebruikt is gebaseerd op de tijd-sinds-1-1-1970. De kans dat er per seconde meer dan 1 record bij komt is klein.

Daar heb ik het database-ID aan toegevoegd (dus eerst het record aanmaken in de DB, dan pas het unique ID invoeren), is eigenlijk altijd uniek. Zelfs als er 100 binnen hetzelfde moment iets willen wegschrijven, omdat ze automatisch een uniek ID krijgen.

Hier zit wel een weakspot in, die ik zelf heb afgevangen met een tijdslimiet. Maargoed, ik moest dan ook iets genereren wat voor "minstens een half uur" uniek was, niet eeuwig.

I'm not a complete idiot. Some parts are missing.
.Gertjan.: Ik ben een zelfstandige alcoholist, dus ik bepaal zelf wel wanneer ik aan het bier ga!


  • DRaakje
  • Registratie: Februari 2000
  • Niet online
Waarom niet omgekeerd, gewoon je database al vullen met een baklading nummers, en daar een ongebruikte uit halen?

  • mrc4nl
  • Registratie: September 2010
  • Laatst online: 11:17

mrc4nl

Procrastinatie expert

DRaakje schreef op zaterdag 07 januari 2012 @ 21:50:
Waarom niet omgekeerd, gewoon je database al vullen met een baklading nummers, en daar een ongebruikte uit halen?
je database volproppen met 1 miljoen records met gegevens die je later weg gaat gooien, lijkt me geen efficient idee

ora et labora


  • Rmg
  • Registratie: November 2003
  • Laatst online: 15:57

Rmg

Waarom niet een autoincrement tabel die je seed met 100000000?

Of is het echt belangrijk dat het niet opvolgend is?

  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
Rmg schreef op zaterdag 07 januari 2012 @ 21:52:
Waarom niet een autoincrement tabel die je seed met 100000000?

Of is het echt belangrijk dat het niet opvolgend is?
Liefst random inderdaad!

  • krvabo
  • Registratie: Januari 2003
  • Laatst online: 20-11 19:54

krvabo

MATERIALISE!

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//even quasi-code
$sSql = " SELECT id FROM ticket ";
$aRows = select_rows($sSql);

$aIds = array();
foreach($aRows as $aRow) {
  $aIds[] = $aRow['id'];
}

$iCounter = 0;

do {

  $iUniek = rand(1, 999999999); // kan '1' uitkomen, maar ook '4251233'
  $sId = str_pad($iUniek, 9, '0', STR_PAD_LEFT); // maak hem 9 lang met 0 ervoor

  $iCounter += 1; // increment $iCounter

} while( in_array($sId, $aIds) && $iCounter < 100000 );
// zolang gegenereerd id in de array staat, en het aantal keer dat het geprobeerd is minder is dan 100k (beveiliging)

// nu heb je een uniek id en kun je die gebruiken


Zoiets voldoet volgens mij aan je wensen?

Uiteraard moet 'id' in je db dan voor de handigheid wel een string worden ipv een int, anders moet je bij alle weergaves weer padden.

[ Voor 9% gewijzigd door krvabo op 07-01-2012 21:55 ]

Pong is probably the best designed shooter in the world.
It's the only one that is made so that if you camp, you die.


  • Firesphere
  • Registratie: September 2010
  • Laatst online: 24-11 23:34

Firesphere

Yoshis before Hoshis

DRaakje schreef op zaterdag 07 januari 2012 @ 21:50:
Waarom niet omgekeerd, gewoon je database al vullen met een baklading nummers, en daar een ongebruikte uit halen?
En toen was je bak leeg? Of, vooral, bij de return...

Dan belast je de server excessief, om 1 record. Probeer het aantal records ook effectief nuttig te laten zijn.

Tenzij het een site is met meer dan 60 bezoekers per seconde, is mijn oplossing zoals eerder genoemd, denk ik het beste.

Check de array, en direct voor schrijven, nog een keer checken. Gaat het toch mis, genereer een nieuwe unieke code en check die. Herhaal.

Dan moet een bezoeker binnen 1 seconde, of zelfs milliseconde een nieuwe code aanvragen voordat het mis gaat als ik de responstijd van MySQL zo zie.

I'm not a complete idiot. Some parts are missing.
.Gertjan.: Ik ben een zelfstandige alcoholist, dus ik bepaal zelf wel wanneer ik aan het bier ga!


  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
X_lawl_X schreef op zaterdag 07 januari 2012 @ 21:46:
[...]


PHP:
1
2
3
4
5
6
do
{
    $code = /* hier iets genereren */
    $query = mysql_query('SELECT code FROM veld WHERE code = ' . $code);    
    
} while (mysql_num_rows($query) != 0)


Niet getest, maar zoiets zal moeten werken.
Hmm, dit lijkt het geen waar ik naar op zoek ben inderdaad.
Ik heb het geprobeerd:
PHP:
1
2
3
4
5
do
{
    $ticketnummer = substr(str_shuffle(str_repeat('123456789',9)),0,9);
    $query = mysql_query('SELECT ticketnummer FROM tickets WHERE code = ' . $ticketnummer);
} while (mysql_num_rows($query) != 0);


Echter krijg ik het volgende terug:

Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in /home/deb42238/domains/yellowstoneband.com/public_html/fpdf/test.php on line 134

  • DRaakje
  • Registratie: Februari 2000
  • Niet online
mrc4nl schreef op zaterdag 07 januari 2012 @ 21:52:
[...]

je database volproppen met 1 miljoen records met gegevens die je later weg gaat gooien, lijkt me geen efficient idee
Je bent ook redelijk een idioot als je er 1 miljoen genereerd, en niet een goede overweging maakt van wat je denkt te gebruiken, als je dan toch met een voorbeeld komt zeg dan gelijk een miljard.

  • mrc4nl
  • Registratie: September 2010
  • Laatst online: 11:17

mrc4nl

Procrastinatie expert

code lijkt mij prima op het oog.
alleen vind ik "aids" toch wel een rare variable naam

ora et labora


  • Snors
  • Registratie: Oktober 2007
  • Laatst online: 18-10 12:34
krvabo schreef op zaterdag 07 januari 2012 @ 21:53:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//even quasi-code
$sSql = " SELECT id FROM ticket ";
$aRows = select_rows($sSql);

$aIds = array();
foreach($aRows as $aRow) {
  $aIds[] = $aRow['id'];
}

$iCounter = 0;

do {

  $iUniek = rand(1, 999999999); // kan '1' uitkomen, maar ook '4251233'
  $sId = str_pad($iUniek, 9, '0', STR_PAD_LEFT); // maak hem 9 lang met 0 ervoor

  $iCounter += 1; // increment $iCounter

} while( in_array($sId, $aIds) && $iCounter < 100000 );
// zolang gegenereerd id in de array staat, en het aantal keer dat het geprobeerd is minder is dan 100k (beveiliging)

// nu heb je een uniek id en kun je die gebruiken


Zoiets voldoet volgens mij aan je wensen?

Uiteraard moet 'id' in je db dan voor de handigheid wel een string worden ipv een int, anders moet je bij alle weergaves weer padden.
Dit zal mogelijk werken maar is het niet makkelijker optelossen volgens de code van X_lawl_X die zag er op het oog wat makkelijker te begrijpen uit.

  • mrc4nl
  • Registratie: September 2010
  • Laatst online: 11:17

mrc4nl

Procrastinatie expert

DRaakje schreef op zaterdag 07 januari 2012 @ 21:54:
[...]


Je bent ook redelijk een idioot als je er 1 miljoen genereerd, en niet een goede overweging maakt van wat je denkt te gebruiken, als je dan toch met een voorbeeld komt zeg dan gelijk een miljard.
wat ik denk dat de TS wil:

kaartjes verkopen met een uniek nummer (9 cijfers)
bij ieder gekocht kaartje komt er een uniek nummer in de database te staan.
dat nummer moet random zijn maar mag maar 1x voorkomen.
je moet gewoon een random nummer met 9 digits hebben, en niet 1 miljoen keer genereren 8)

ora et labora


  • X_lawl_X
  • Registratie: September 2009
  • Laatst online: 17:22
M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:54:
[...]


Hmm, dit lijkt het geen waar ik naar op zoek ben inderdaad.
Ik heb het geprobeerd:
PHP:
1
2
3
4
5
do
{
    $ticketnummer = substr(str_shuffle(str_repeat('123456789',9)),0,9);
    $query = mysql_query('SELECT ticketnummer FROM tickets WHERE code = ' . $ticketnummer);
} while (mysql_num_rows($query) != 0);


Echter krijg ik het volgende terug:

Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in /home/deb42238/domains/yellowstoneband.com/public_html/fpdf/test.php on line 134
Klopt je query wel? Als ik me niet vergis returned mysql_query gewoon een resource tenzij de query niet klopt. [Ik kan me vergissen, normaal gesproken gebruik ik deze functies niet]

  • Firesphere
  • Registratie: September 2010
  • Laatst online: 24-11 23:34

Firesphere

Yoshis before Hoshis

M34nM4chin3 schreef op zaterdag 07 januari 2012 @ 21:54:
[...]


Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in /home/deb42238/domains/yellowstoneband.com/public_html/fpdf/test.php on line 134
geen resultaat dus ;)
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
public function checkCode($code){
    $select = mysql_query('SELECT ticketnummer FROM tickets);
    $array = mysql_fetch_assoc($select);
       if(!in_array($array, $code)){
           mysql_query('INSERT INTO `tickets` stuff);
       }
       else{
           $code = new_generated();
           $this->checkCode($code);
       }
               
}


Dit is quick-and-dirty, kan buggen ;)

I'm not a complete idiot. Some parts are missing.
.Gertjan.: Ik ben een zelfstandige alcoholist, dus ik bepaal zelf wel wanneer ik aan het bier ga!


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 19:56

Creepy

Tactical Espionage Splatterer

Hmja, een (do) while loop schrijven is echt niet zo heel spannend en een select die controleert of je gegenereerde ID nog niet bestaat ook niet. Dat lijkt me vrij makkelijk te combineren lijkt me ;)
krvabo komt met een oplossing die steeds langer gaat dure naar mate je meer ID's in je tabel hebt staan. Ze worden nu allemaal gelezen en sequentieel afgegaan d.m.v. de in_array. Dat doet een database met een select en een index op het ID echt vele maler sneller, en gebruikt ook nog eens een stuk minder geheugen.

Dus probeer nu gewoon eens wat. En probeer dan ook een eventueel fout eerst zelf op te lossen i.p.v. direct hier te posten. Je hebt echt al tips genoeg gekregen om het zelf op te lossen lijkt me ;) Je hebt zelfs al een paar redelijke kant en klare oplossing gehad, iets wat eigenlijk niet de bedoeling is omdat men van kopieren en plakken zo weinig leert ;)

[ Voor 16% gewijzigd door Creepy op 07-01-2012 22:01 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
^ Los van wat Creepy zegt heb je met deze 'trial-and-error' methode ook nog eens kans op race-conditions: wat als nummer 398632 vrij blijkt te zijn voor gebruiker 1, ondertussen komt gebruiker 2 en die krijgt (toevallig) hetzelfde nummer en dat nummer is nog steeds vrij. Vervolgens doet user 1 de insert en krijgt user 2 een foutmelding.

True, de kans is klein en zolang 't niet om facebook proporties gaat en/of geen duizenden gebruikers en/of maar 100 tickets op een 'range' van 0 - 999999999 dan zal 't wel los lopen. En toch zou ik, gegeven de functionele eisen (want anders koos ik eerder voor een GUID oid) gewoon een insert doen met random nummer en een eventuele exception vangen en opnieuw proberen met een ander random nummer tot er geen exception meer optreedt (en dus de insert gelukt is == uniek nummer).

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Pagina: 1

Dit topic is gesloten.