->Hi Daniweb-Web Developers.
->I'm using PhP 5.2.5,WAMP 5,MySQL 5.
-I'LL TRY TO EXPLAIN IN DETAILS THE WHOLE STORY:-

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

1: I've declared a global variable dynamic array ALPHABETS_COMBINATION.
2:It is populated with a group of 3 Alpha combination AAA-ZZZ in a function : Generator($ALPHABETS)
3:Once the Buttonn click event is triggered I count the records in My table 'Items' to get the total of records
4:And For each record the Function is called to generate the combination and pick one for a record say record 1
5:The picked combination is then checked in another table 'Cat' to see if it exists
6:If it does exist the function produces another combination for the same record 1
7:If the combination does not exist in table 'Cat' then the record is assigned the combination and saved in the 'Cat' table
8:Then the process is repeated for the next record in 'Items' table for say record 2

--------------------------------------------------
->Now this is where I get the error:
Fatal error: Allowed memory size of 10485760 bytes exhausted (tried to allocate 35 bytes) in C:\wamp\www\My_Site_Name\My_Classes\class_bulk_data.php on line 423 (Where the variable is being repopulated with alphabet combinations for the next record)
->I have tried to use:
ALPHABETS_COMBINATION=null
unset(ALPHABETS_COMBINATION)
ALPHABETS_COMBINATION=array()
->All wont do every time the next recor start it produces the same error any advice what should I do?
->Any help will be appreciated...

Recommended Answers

All 17 Replies

Member Avatar for iamthwee

First question... Why?

What are you doing. It sounds daft.

Thank you iamthwee for your response,
To make it clear I am generating an ID for each product in table 'Items' once it is to be saved in table 'Cat'.

AN IDEA IS LIKE THIS:

I have a shop but I do purchase My products from whole sellers,so once the bucket I ordered is received from a whole seller in table 'Items' I do unpack them in My table 'Cat'.
The products must have unique identities in table 'Cat' and so the Identity is in a format PRD/Numbers/Alphabets
NOTE:
Alphabets Must have the combination form AAA-ZZZ, the alphabets change in sequency such thet second alphabets from the Right:AAA will change to B once all the alphabets of the first alphabet from Right AAA has managed to loop upto 'Z' and the process restarts with ABA up to AZZ so that the First alphabet from Left AZZ changes to BAA and the whole process starts to loop the first alphabets form Right BAA to BAZ to change the second alphabet from Right untill all the three alphabets reaches ZZZ.
At this point is where I change Numbers as they range from (00-99) say the whole process above was only operated while number was PRD/01/AAA to PRD/01/ZZZ then the number changes to PRD/02/AAA after reset then the whole process starts over again.
WHY I just want to have a large pool of Identities with ther small range of numbers rather than letting My numbers flow up to say 999 or above.
I tried to use some functions like rand() and some for randomizing the alphabets but it seems that alphabets repeats so fast when I have large number of 'Items' for the same number 01 and so I wrote the codes with php to do the combination for Me and lastly I combine them with My numbers but then for only one record it works fine but when I loop for the second record in table 'Item' thats when error comes.
Thanks iamthwee.
Any other way round this will be appreciated.

Member Avatar for diafol

In order to increment this type of key, I'd probably use a base26 (hexavigesimal) function:

<?php

function s26ToNum($s26)
{
    $array = array_combine(range('A','Z'),range(1, 26));
    $num = 0;
    $num = ($array[$s26{0}] - 1);
    for ($i = 1; $i < 3; $i++) {
        $num *= 26;
        $num += ($array[$s26{$i}] - 1);
    }
    return $num;
}

function numToS26($number)
{
    $flip = range('A','Z');
    $s26 = "";
    while ($number > 0)
    {
        $remainder = ($number) % 26;
        $s26 = $flip[$remainder] . $s26;
        $number = ($number - $remainder) / 26;
    }
    return $s26;
}


function getNextId($str, $maxSize = 3, $digitSize = 2, $separator = '/')
{
    list($prefix,$digits,$s26) = explode($separator, $str);
    $newNum = s26ToNum($s26) + 1;

    $newS26 = numToS26($newNum);  

    if(strlen($newS26) > $maxSize)
    {
        $newS26 = substr($newS26, 1);
        $digits = (int) $digits;
        $digits = str_pad($digits + 1, $digitSize, '0', STR_PAD_LEFT);  
    }
    if(strlen($newS26) < $maxSize)
    {
        $newS26 = str_pad($newS26, $maxSize, 'A', STR_PAD_LEFT);    
    }
    return implode($separator, array($prefix,$digits,$newS26)); 
}
//TEST
$strArray = array('PRD/01/ZAZ','PRD/62/ZAP','PRD/87/AAZ','PRD/01/PPP','PRD/04/ZZZ','PRD/10/JKP','PRD/10/ZZZ');
foreach($strArray as $str)
    echo $str . ' => ' . getNextId($str) . '<br />';

?>

Test seem to work. However, this is dependent on retrieving the last record just in order to get the next. Also a PITA if inserting more than one record at a time.

I suggest that you store id values as plain autoincrement (integers) and either use a function to insert the resulting product code in a code field or dynamically create the product codes when you need them displayed.

Oh - and 'Fetal error' made me think of a baby eating the contents of his diaper :)

Thank you diafol, I tried the code but it seems that the alphabet part still repeating with the same numbers.
Please try this so as to show you what I have so far,but you will need an index.php with the following code:

<html>
<head>
<?php
include("identity.php");
$Rand=new Product_Identities();
?>
<title>RANDOM ID GENERATOR:</title>
</head>
<body>
<?php 

    $Rand->spm_engine();

?>
</body>
</html>

Then paste the following in another file as shown above in include part identity.php:

<?php

class Product_Identities
{
/*=============================================================================================================================*/
private $Maxmum,$Group_A,$Group_B,$Group_C,$ALPHABETS_COMBINATION=array(),$SPM_IDENTITY;

/*******FIRST GROUP C RANDOM GENERATION*******/         
private function Group_C()
    {
        $this->Group_A=array_merge(range('A','Z'));
        $this->Group_B=array_merge(range('A','Z'));
        $this->Group_C=array_merge(range('A','Z'));

        $Max=count($this->Group_C);
        for($Numb=0;$Numb<=$Max;$Numb++)
        {
            if($Numb<$Max)
            {
                $C=$this->Group_A[0].$this->Group_B[0].$this->Group_C[$Numb];
                $this->Generator($C);
            }
            elseif($Numb==$Max)
            {
                $this->Group_B();
            }
        }
    }
        /*------FIRST GROUP C RANDOM GENERATION ENDS------*/

    /*******SECOND GROUP B RANDOM GENERATION*******/    
private function Group_B()
    {

        $this->Group_A=array_merge(range('A','Z'));
        $this->Group_B=array_merge(range('A','Z'));
        $this->Group_C=array_merge(range('A','Z'));

        $Max=count($this->Group_B);

        for($Numb=1;$Numb<=$Max;$Numb++)
        {
            if($Numb<$Max)
            {   
                for($NumIn=0;$NumIn<$Max;$NumIn++)
                {
                    if($NumIn<$Max)
                    {
                        $B=$this->Group_A[0].$this->Group_B[$Numb].$this->Group_C[$NumIn];
                        $this->Generator($B);
                    }
                }    
            }
            elseif($Numb==$Max)
            {
                $this->Group_A();
            }
        }
    }
        /*------SECOND GROUP B RANDOM GENERATION ENDS------*/

    /*******THIRD GROUP A RANDOM GENERATION*******/
private function Group_A()
    {
        $this->Group_A=array_merge(range('A','Z'));
        $this->Group_B=array_merge(range('A','Z'));
        $this->Group_C=array_merge(range('A','Z'));

        $Max=count($this->Group_A);

        for($Numb=1;$Numb<=$Max;$Numb++)
        {
            if($Numb<$Max)
            {
    /*-----INNER LOOP FOR RESTARTING THE GROUP B SET-----*/
                for($NumInB=0;$NumInB<=$Max;$NumInB++)
                {
                    if($NumInB<$Max)
                    {
                    /*-----INNER LOOP FOR RESTARTING THE GROUP C SET-----*/
                        for($NumInC=0;$NumInC<$Max;$NumInC++)
                        {
                            if($NumInC<$Max)
                            {
                                $A=$this->Group_A[$Numb].$this->Group_B[$NumInB].$this->Group_C[$NumInC];
                                $this->Generator($A);
                                unset($A);  
                            }
                        }
                    /*-----INNER LOOP FOR RESTARTING THE GROUP C SET ENDS-----*/
                    }
                }
        /*-----INNER LOOP FOR RESTARTING THE GROUP B SET ENDS-----*/
            }
            elseif($Numb==$Max)
            {
                    break;
            }
        }
    }
        /*------SECOND GROUP A RANDOM GENERATION ENDS------*/

    private function Generator($ALPHABETS)
    {           
         $this->Maxmum=$this->Maxmum+1;
         $Limit=count($this->ALPHABETS_COMBINATION);
         if($Limit<$this->Maxmum)
         {
         $this->ALPHABETS_COMBINATION[]=$ALPHABETS;
         }

    }

private function spm_engine()
    {
        $this->Group_C();

        /*
        THE LOOP BELOW IS THE ONE HOLDING MY NUMBERS FROM 00-99
        I JUST PUT THE RANGR OF 1-2 i.e, $Number_Range=1;$Number_Range<3;$Number_Range++
        FOR DEMO AS TOO MANY WILL EXAUST THE MEMORY
        */
        for($Number_Range=1;$Number_Range<3;$Number_Range++)
            {
                $Range_Length=strlen($Number_Range);

                if($Range_Length==1)
                    {
                        $NUMBERS_SET="00".$Number_Range;

                        for($ALphabet_Range=1;$ALphabet_Range<=($this->Maxmum-1);$ALphabet_Range++)
                            {                                   
                            if($this->ALPHABETS_COMBINATION[$ALphabet_Range]!="SEX")
                                {
                                $this->SPM_IDENTITY="PRD/".$NUMBERS_SET."/".$this->ALPHABETS_COMBINATION[$ALphabet_Range];
                                echo $this->SPM_IDENTITY;
                                }
                            }
                    }

                elseif($Range_Length==2)
                    {
                        $NUMBERS_SET="0".$Number_Range;

                        for($ALphabet_Range=1;$ALphabet_Range<=($this->Maxmum-1);$ALphabet_Range++)
                            {
                            if($this->ALPHABETS_COMBINATION[$ALphabet_Range]!="SEX")
                                {
                                $this->SPM_IDENTITY="PRD/".$NUMBERS_SET."/".$this->ALPHABETS_COMBINATION[$ALphabet_Range]."\n";
                                echo $this->SPM_IDENTITY;
                                }
                            }
                    }

                elseif($Range_Length==3)
                    {
                        $NUMBERS_SET=$Number_Range;

                        for($ALphabet_Range=1;$ALphabet_Range<=($this->Maxmum-1);$ALphabet_Range++)
                            {
                            if($this->ALPHABETS_COMBINATION[$ALphabet_Range]!="SEX")
                                {
                                $this->SPM_IDENTITY="PRD/".$NUMBERS_SET."/".$this->ALPHABETS_COMBINATION[$ALphabet_Range]."\n";
                                echo $this->SPM_IDENTITY;
                                }
                            }
                    }

            }
    }
}
?>

From there then I hope I am CLEAR now with what I want to do.
I'll be happy to have some suggestions.

Member Avatar for diafol

Thank you diafol, I tried the code but it seems that the alphabet part still repeating with the same numbers.

Not sure wjat you mean. Replace the test array with this...

//TEST
$strArray = array
(
    array('test'=>'PRD/01/ZZA','next'=>'PRD/01/ZZB'),
    array('test'=>'PRD/62/ZAP','next'=>'PRD/62/ZAQ'),
    array('test'=>'PRD/87/AAZ','next'=>'PRD/87/ABA'),
    array('test'=>'PRD/01/PPP','next'=>'PRD/01/PPQ'),
    array('test'=>'PRD/04/ZZZ','next'=>'PRD/05/AAA'),
    array('test'=>'PRD/10/JKP','next'=>'PRD/10/JKQ'),
    array('test'=>'PRD/10/ZZZ','next'=>'PRD/11/AAA')
);



foreach($strArray as $item)
    echo $item['test'] . ' ( EXPECTED = ' . $item['next'] . ') => ' . getNextId($item['test']) . '<br />';

And you should see that it works correctly - or at least correctly as I understand it should work.

The next id after PRD/10/ZZZ will be PRD/11/AAA

Isn't that right?

Member Avatar for iamthwee

That is the worst part number system I have ever seen. There are so many things that could go wrong.

commented: It is indeed a bad idea +14

->Let Me work on it diafol.
iamthwee

That is the worst part number system I have ever seen. There are so many things that could go wrong.

,I hope here at DANIWEB what We do is try to present our ideas that may be in a drab language or so, and form there others with a well structured way may help to improve it I hapo that is the part diafol and others do.
So finding that I have a deadly way of presenting My idea and you have understand what I may be in need of then it was My expectation that you show what you got instead of trying to accuse an idea which the one presenting it also agree that it is some what crap. So should I use your lines to solve My problem? And how anyway?
Thank you for all your contributions.

Member Avatar for iamthwee

I do agree my penultimate reply was unhelpful so I'll try to elaborate.

bUT you have to explain a few things.

  1. Is it absolutely necessary to have the end of the part number end AAA-ZZZ?

I'm guessing you just thought that was a good idea so you haven't considered other options.

Let's look at the issues. One, any number system that uses a permuation generator has a bad time complexity, I'm guessing this has a 'factorial' type complexity. If you were to add another letter to the end it gets even worse - AAAA-ZZZZ. You've got to consider this as your database grows.

Two, you have to do a look up in your database first and then generate the next available slot. This is horrible, let's imagine you've got 1000 users using your system and each one is inserting 20 new part numbers.

Can you imagine the strain on your database, first doing a lookup and then generating a new number. What about concurrent users trying to add partnumbers at roughly the same time? What happens then?

See, it is already getting quite hairy. The best solution, is to generate an incremental string at the end.

So +1..+2...+3

OK you might get a bigger partnumber string than you intend but the pros outweigh the cons.

Typically your part number would look like this using 'Manufactured cylinders' as an example.

CYL-D25-L300-0001
CYL-D25-L300-0002
CLY-D30-L800-0001

CYL = cylinder
D25 = diameter 25mm
L30 = Length 300mmm
0001 = is the unique type, 0002 if it is slightly different (manufacturing type or made from another material)

That's the way most Manufacturing ERP solutions do it, as far as I'm aware.

Member Avatar for diafol

I still think that it's easier to have an autoincrement primary key. Even the 'manufacturing example' index can be constructed on the fly from other fields.

The complexity here (the AAA-ZZZ example) also comes from the 'overflow' from when 01/ZZZ -> 02/AAA - by the way A = 0 (not 1) and Z = 25 (not 26).
If you just kept to A-Z, then...

ZZY, ZZZ, BAAA, BAAB...

It makes sense!

After I presented the original codeI've found a far easier method and this involves base_convert(). However, it involves the traditional digits and letters [0-9, A-P] instead of A-Z for base26

So your ZZY, ZZZ, BAAA, BAAB would be: PPO, PPP, B000, B001

That system may be easier. It certainly cuts down on the number of characters compared with decimals (base10), BUT as you have at least 10 or 11 digits as integers for autoincrement - far more than you could possibly need - I am confused as to why you need to develop this rather weird system.

->Phewww!,
All the advice are appreciated.
Though the PRD/NNN/AAA seems to suit the needs here with Me as iamthwee guessed what I thought.
I want those Identities to be generated and saved in My Database table then may be what I dont worry for is that I'm the one who is only going to access the Identities when I receive the products in My Items so iamthwee lets start worrying from here as there wont be any multiple concurrency.
I have managed to save a bunch of them by now I think My last record was PRD/99/AIW so I think I'll only have PRD/99/AZZ for the first generation and wait them to end for the next generation.
Concerning the checking the existence I have acolumn with the status of an ID '0' for available '1' for taken and by using the fetch array I hope I'll be sorting out only with status ='0' and start working with them.
Does it sound any good?...

Member Avatar for diafol

Does it sound any good?...

No. I don't think I'd do this myself, it seems pretty pointless. I can't see what's wrong with having an autoincrement id and then calculating the product code when required. Having to look up available names or searching for the last record to get the code in order to insert a new one, is a bit daft (sorry, no offence).

So 99/AIW to my way of thinking represents the integer 1722678.

(98 * 26^3) + (0 x 26^2) + (8 x 26^1) + (22 x 26^0)

You have this number of products?

You have this number of products?

More than that! Thats why I said I want to utilize as many possible available alphabets combination only for 1 numeral.
the PRD/NNN/AAA I may say here is what each part means:

1.PRD=Product
2.NNN=Numeric generation for the Products alphabetical combination.
3.AAA=Alphabetical ID for the Numeric generation.

The genereted ID for product will distinguish one type of product with another within the same number generation say for example:
All beverages will be of number generation 001 but the individual beverage ID is distinguishe by alphabets part from one to another:
1.Coca~Cola PRD/001/AAA
2.Pepsi PRD/001/AAB

And for Motorvehicles will be holding number generation 002 and as well their individual distinction will be based on the alphabet part:
1.Carina PRD/002/AAA
2.Benz PRD/002/AAB
Thats why I am in need of maintaining the format as I provided.
Is it clear for that?...

Member Avatar for diafol

OK, that's different to what I thought, so the numeric aspect has no relationship to the alphabetic increment.

That makes it a bit more complicated. Are you still insisting on a random generator for the alphabetic part or is an incremental permissible?

I think if I do catch with what you mean by

an incremental permissible?

that the alphabetical part do increment from A to Z then "Yes" I do insist as You can see I will persist with the use of 001 with the combination of all the posible alphabets combination from AAA to ZZZ but otherwise if its daft then I'll agree with a good way around this...

Member Avatar for iamthwee

This system is prone to failure... I'm hoping it doesn't involve payments of any sort, as a result I'm stepping down. I don't want to play any part where information can be corrupted all for the sake what exactly? I'm totally unsure -the numbers AAA-ZZZ are completely meaningless.

Diafol he's all yours!

Member Avatar for diafol

Using AAA->ZZZ will give you 26 + 26^2 + 26^3 = maximum 18,278 products for each 'category' (number part) - possibly 18,277 if you have to start at AAB instead of AAA (AAA=0, AAB=1).

As the number part is no longer linked to the alphabetic part, then you can store a maximum of 18,259,722 products (using a 3 digit number part, going from [00]1 to 999)

You realise that you have to make a call to the db to find the last inserted record for that 'category' before simply inserting your new record?

You have a number of possibilities, here's one...

The all-in method
product_id [PK, varchar] | product_name [varchar] ...
PRD/003/AGP | 'Renault Scenic 1993 Gearstick'

Trying to retrieve the last inserted value (AGP) for a particular 'category' (003) is complicated, but not impossible.

SELECT SUBSTRING(product_id,9) AS lastentry FROM products WHERE product_id LIKE CONCAT('%/',:category,'/%') ORDER BY product_id DESC LIMIT 1

If you make category = '003', then let's say lastentry='AGP' is returned.
We now need to increment AGP -> AGQ

Here's a simple, yet verbose script...

function getNext($code)
{
    if(!$code) return 'AAA';
    $alpha = range('A','Z');
    $flip = array_flip($alpha);
    $new = array();

    if($code{2} == 'Z')
    {
        $new[2] = 'A';
        $add1 = true;
    }else{
        $new[2] = $alpha[($flip[$code{2}] + 1)];    
    }
    if($code{1} == 'Z' && isset($add1))
    {
        $new[1] = 'A';  
        $add2 = true;
    }elseif(isset($add1)){
        $new[1] = $alpha[($flip[$code{1}] + 1)];
    }else{
        $new[1] = $code{1}; 
    }
    if(isset($add2))
    {
        $new[0] = $alpha[($flip[$code{0}] + 1)];
    }else{
        $new[0] = $code{0}; 
    }
    ksort($new);
    return implode('',$new);
}

echo getNext('MZZ'); //should return NAA

Let Me thak You for Your great help diafol...
I hope all the suggestions You provided increased My BLS ~ Brain Library System.
But I noticed something while giving Me the posible solutions though its too late as We have gone farther, I hope may be I based on the root of the "Discussion" that the only problem here is running out of Memory while executing My codes to populate the Generated ID's for My table.
But from trying to explain this:

First question... Why?
What are you doing. It sounds daft.

May be thats where We got lost,though I realized its helpfull too. I wanted a way that will help Me to get rid of the "Memory Exhaustion" Error.
What I have tried is to limit small range of Number for My ID's then next round I pickup where I ended and provide another range and so I've populated as to My exhaustion without the Error.
But before I mark the thread as solved I'll give You an explanation of the whole Idea on My perspective view now and You may worn Me of anything then thas it I mark the discusion as solved.

NOW:

I have alredy the table with already made ID's for Me what I'll be doying is when I receivve the Products in My "Items" table I take their count and then go to My ID's table and pick all the ID's with the Status of '0' (Meaning its not taken) and then starts to pick one product in a while loop from "Items" and give them the ID's one at a time while the loop is terminated up on the end of the count of the products and once the product from "Items" has been given an ID it is Inserted in "Cart" table then taken ID's Field Status is Updated to '1' as taken and thats it tested it and its working as I pictured it.
Thats all I have the only thing I'm bound to up to now is populating the ID's.
Thanks Once again.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.