Learning PHP - Would like advice on something

Discussion in 'PHP' started by christoph, Jul 21, 2012.

  1. #1
    Hello all,

    I am currently learning php and i must say I am very much enjoying it. Its my first ever programming language and I am getting a real buzz from it (thats the inner nerd from me comming out).

    I was wondering if someone could help me or point me towards a good article. I am building my first ever script which will tag on to a wordpress plugin. The idea is to make a random coupon code generator.

    I have done the first bit, which is generating the random element. See below in red

    <?php

    $randomcoup = rand(1, 100);

    $thankyou = "Your complimantary coupon code is: ";

    $code1 = "15OFFE"; /* 15% off code*/
    $code2 = "25OFFE"; /* 25% off code*/
    $code3 = "45OFFE"; /* 45% off code*/

    $datesaving = "07/30/2012"; /* active date*/

    $saving15 = ", which will give you a 15% discount on your next purchase! The code will be active to use next Friday ( ";
    $saving25 = ", which will give you a 25% discount on your next purchase! The code will be active to use next Friday ( ";
    $saving45 = ", which will give you a 45% discount on your next purchase! The code will be active to use next Friday ( ";

    $dayonly = " ) for 1 day only. Enjoy";

    if( in_array( $randomcoup , range( 1 , 33 ) ) ) {
    echo $thankyou . " " . $code1 . "" . $saving15 . "" . $datesaving . "" . $dayonly . "" . ".";
    }

    if( in_array( $randomcoup , range( 34 , 66 ) ) ) {
    echo $thankyou . " " . $code2 . "" . $saving25 . "" . $datesaving . "" . $dayonly . "" . ".";
    }

    if( in_array( $randomcoup , range( 67 , 100 ) ) ) {
    echo $thankyou . " " . $code3 . "" . $saving45 . "" . $datesaving . "" . $dayonly . "" . ".";
    }

    ?>


    As you can see, the script above picks a number between 1 and 100. If its say 25, it actions the first if statement and echos a specific coupon code.

    What I want to do is connect to the database where the coupon data is stored, and populate the $code and $datesaving variable with the data I get from the database. That way I dont have to change the php script every week to put in the new codes and expiry dates.

    I have successfully managed to connect to the database and extract the data for the coupon codes where they have been sorted. In this case, all the data is stored in a single cell and it looks like this (I have also assigned all this data to a single variable string):


    (541, 'jigoshop_coupons', 'a:8:
    {
    s:8:"15OFFABC";a:7:{s:4:"code";s:8:"15OFFABC";s:6:"amount";s:2:"15";s:4:"type";s:7:"percent";s:8:"products";a:0{}s:9:"date_from";i:1342742400;s:7:"date_to";i:1343260799;s:14:"individual_use";s:3:"yes";}
    s:8:"25OFFABC";a:7:{s:4:"code";s:8:"25OFFABC";s:6:"amount";s:2:"25";s:4:"type";s:7:"percent";s:8:"products";a:0{}s:9:"date_from";i:1342742400;s:7:"date_to";i:1343260799;s:14:"individual_use";s:3:"yes";}
    s:8:"45OFFABC";a:7:{s:4:"code";s:8:"45OFFABC";s:6:"amount";s:2:"45";s:4:"type";s:7:"percent";s:8:"products";a:0{}s:9:"date_from";i:1342742400;s:7:"date_to";i:1343260799;s:14:"individual_use";s:3:"yes";}
    }', 'yes');



    (Its actually all in one line, but I have put it into different lines to see each code. as you can see, there are 3 coupon codes, called : 15OFFABC, 25OFFABC , 45OFFABC)

    What I need to do, is somehow extract the code (e.g. the "s:4:"code";s:8:"15OFFABC", and assign that to the relevant variable (in this case - $code1). There is always going to be a constant which is the amount (e.g. s:6:"amount";s:2:"15";).

    So I was wondering, maybe some sort of search could look for the coupon code with the amount of "15". If there is an amount with 15, return the "code" ("s:4:"code";s:8:"15OFFABC") and assign that value to the relevant code variable (e.g. $code1).

    I would also watch to extract the expiry date value and assign that to a variable as well (s:7:"date_to";i:1343260799). I already know how to convert this into a readable date (after much googleing lol). Also note the expiry date will always without fail, be the same date for each coupon. Thats why I have only gave it one variable in the php.

    Basically, there will only ever be one coupon code with the amount 15, one with the amount 25 and one with the amount 45, so I assume this is the best way to do it. If so, I have no idea what code I would need to write in order to do that. I would love suggestions!!

    Thank you
     
    Last edited: Jul 21, 2012
    christoph, Jul 21, 2012 IP
  2. BRUm

    BRUm Well-Known Member

    Messages:
    3,086
    Likes Received:
    61
    Best Answers:
    1
    Trophy Points:
    100
    #2
    Hi Christoph, glad you're enjoying PHP. It was also my first programming language and still remains my favourite today despite now knowing several more languages.

    First, I'd say the best thing to do is buy some books. I highly recommend O'reilly's books on PHP and some include SQL, which is very useful.

    Next, for the sake of clarity I also recommend using camel-case labelling, which means splitting variables as words and capitalising the beginning character of each word after the first and also capitalising the beginning character of every word for functions and classes. This was first used in Pascal and there are many variations, but the one I use is done like so:

    
    <?php
    
    # Camel case for variables
    $first[B]V[/B]ar = 100;
    $var = 67;
    $a[B]M[/B]uch[B]L[/B]ongerVar = 1000;
    
    # Camel case for functions and classes
    function MyFunction()
    {
        ...
    }
    
    // Use full capitalisation for classes that will be instantiated - those that will become objects
    private class MyClassObject()
    {
        ...
    }
    
    // This won't be instantiated as it's static, so label like a variable
    public static class myStaticClass
    {
        ...
    }
    
    ?>
    
    Code (markup):
    I also recommend K&R style indent notation for code blocks. It was invented by the creators of C (K&R named after the two men). While I am quite an anal person, I think it's much easier to debug and makes blocks of code and nesting much more manageable, like so:

    
    <?php
    
    // This...
    function MyFunc($args)
    {
        ...
    }
    
    // ... instead of this
    function MyFunc($args){
        ...
    }
    
    ?>
    
    Code (markup):
    Now, about your code can you elaborate on the data type you've placed the database data in to? If I'm understanding you correctly you're not placing the data into an array, which is the most powerful data structure in my opinion. No search is needed, all you need to do is refer to the index in the array where the coupon is.

    By the way, please make sure you are using PDO (PHP Data Objects) to handle your database. Using mysql_* commands like mysql_query is now deprecated.

    Note: Never ever ever place all your data in a single cell. This defeats the object of using a relational database! The whole purpose of a database is to put each type of data in its own cell so that you can use SQL commands to retrieve them. There are dozens of great SQL commands and some of them, such as JOIN and UNION, allow separate tables to be merged or treated as a single set allowing very powerful functionality.

    Here's an example of how you can retrieve voucher data from a database:

    Assume the database structure is:

    {id, vouchercode, saving, datefrom, dayto}
    Code (markup):
    Example row:

    {1, 150FFABC, 0.15, 12345, 98765}
    Code (markup):
    
    
    <?php
    
    // Instantiate DB PDO object
    $db = new PDO("mysql:dbname=yourdatabase;host=127.0.0.1", "username", "password");
    // Prepare the SQL query to match all vouchers in the table
    $q = $db->prepare("SELECT * FROM voucherTable");
    // Perform the query
    $q->execute();
    
    // Iterate through each row in the table
    while($row = $q->fetch(PDO::FETCH_ASSOC))
    {
        // Place each row in array
        $voucherArray[] = array($row["vouchercode"], $row["saving"], $row["datefrom"], $row["dayto");
    }
    
    // Now to get any of the vouchers' details, just use the index
    $aVoucherCode = $voucherArray[1][0];
    $aVoucherSaving = $voucherArray[1][1];
    $anotherVoucherCode = $voucherArray[2][0];
    // and so on..
    
    ?>
    
    
    Code (markup):
    You can use string keys so you don't have to use numeric indexes if you wish, however they both do the same thing.

    I hope this helps. Feel free to shoot me a PM or ask more questions here if you need more help.

    Lee.
     
    Last edited: Jul 21, 2012
    BRUm, Jul 21, 2012 IP
  3. christoph

    christoph Active Member

    Messages:
    279
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    55
    #3
    Firstly Lee, thanks for the detailed reply. I really appreciate all your tips and advice, I will try to take them all on board. I have a friend at work who knows php and he said the community is really helpful at sharing knowledge, I think you have just proven him correct!

    Unfortunately - All of the data is in one single cell (not a row or column for each coupon, all in one cell!!!). I agree that its not ideal but as this was done by the maker of the plugin, I don't want to start changing that around until I become more confident.

    I am merely looking to draw that data out of the cell and then do what I need with it.

    What I have managed to do is connect to the database, find the table and draw out the value in this single cell. I have done an echo on to a web page and I can see its returning everything from that cell.

    A.jpg

    Here is the code I have used to achieve that:

    <?php

    define('DB_NAME', '***');
    define('DB_USER', '***');
    define('DB_PASSWORD', '***');
    define('DB_HOST', '***');

    $link = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);

    if (!$link) {
    die('Could not connect: ' . mysql_error());
    }

    $db_selected = mysql_select_db(DB_NAME, $link);

    if (!$db_selected) {
    die('Cant use ' . DB_NAME . ': ' . mysql_error());
    }

    echo '<p>Connection successful</p>';



    $data = mysql_query("SELECT * FROM wp_options WHERE option_id = '541'")
    or die(mysql_error());


    while($info = mysql_fetch_array( $data ))
    {
    $test = $info['option_value'];
    echo $test ;
    }



    What the echo "$test ;" returns is exactly what I posted in my first message (second set of red code) (but bare in mind, I put a few "br" html codes in there to make it more readable on this forum. Its actually all in one line).

    You can also see the output of it here:

    http://i13posefactory.com/coupon-code-add.php

    So my dilemma is, after getting this one value into a single string variable, what next? How can I start splitting up the data from this one variable so I have a variable for each "coupon code".

    Apologies If I have miss-understood your reply and the answer is already there, but I think your assuming the data for a single coupon code will be in each row, which in this case unfortunately it is not. :(

    Thanks again

    p.s I plan to tidy the code at some point and use the PDO method instead. :D
     
    Last edited: Jul 21, 2012
    christoph, Jul 21, 2012 IP
  4. BRUm

    BRUm Well-Known Member

    Messages:
    3,086
    Likes Received:
    61
    Best Answers:
    1
    Trophy Points:
    100
    #4
    You're very welcome Christoph.

    Glad you'll be taking the initiative later and reading up on PDO and such.

    Right, luckily I recognise that the format of the data in your table is the result of the serialize() function. The plugin creator will have used that function, so a simply using the unserialize() function will turn the string back into the object (or array) that it was originally.

    What the serialize() function does is take an existing and populated data structure, like and array or class object, and encode it into a simple string with delimiters (the semi colons that you see) so it can be stored in a flat file and easily decoded back to the data structure with the deserialize() function.

    The plugin programmer should have known better though, it's highly discouraged to throw a serialized string into a table. Each cell of the array should be its own column in the table.

    Looking at the curly braces of the serialized string you've given I get the feeling it's a multidimensional array or array of arrays.

    EDIT: I took the string that you provided on the webpage and unserialized it myself. I then passed it to the print_r() function in order to get a human readable representation of the structure. As I thought it's an array of arrays:

    
    Array
    (
        [15OFFABC] => Array
            (
                [\code] => 15OFFABC
                [amount] => 15
                [type] => percent
                [products] => Array
                    (
                    )
    
                [date_from] => 1342742400
                [date_to] => 1343260799
                [individual_use] => yes
            )
    
        [25OFFABC] => Array
            (
                [\code] => 25OFFABC
                [amount] => 25
                [type] => percent
                [products] => Array
                    (
                    )
    
                [date_from] => 1342742400
                [date_to] => 1343260799
                [individual_use] => yes
            )
    
        [45OFFABC] => Array
            (
                [\code] => 45OFFABC
                [amount] => 45
                [type] => percent
                [products] => Array
                    (
                    )
    
                [date_from] => 1342742400
                [date_to] => 1343260799
                [individual_use] => yes
            )
    
    )
    
    Code (markup):
    Note: I had to put a backslash in front of the 'c' making [\code] because it interferes with this forum's BB code, as there is already a BB code tag called [ code]!

    So once you've deserialized the string back to an array, you can simply access its properties like so:

    
    $array = unserialize($test);
    $voucherCode = $array["45OFFABC"]["code"];
    $voucherAmount = $array["45OFFABC"]["amount"];
    $voucherType = $array["45OFFABC"]["type"];
    
    Code (markup):
    As you can see it's not designed in such a good way as your plugin creator used the voucher code as the index, d'oh!

    It would be so much better if it was something like:

    
    $voucherCode = $array[0]["code"];
    $anotherCode = $array[1]["code"];
    
    Code (markup):
    Serialize() can be very useful as you can encode an entire class object as a string safe for storing and later decoding.

    Does this give you a better idea of what that string is?
     
    Last edited: Jul 21, 2012
    BRUm, Jul 21, 2012 IP
  5. lolpasslol

    lolpasslol Peon

    Messages:
    860
    Likes Received:
    5
    Best Answers:
    0
    Trophy Points:
    0
    #5
    Carry on carry on ,your love for PHP make your way to go.
    It is my first language also.
    I am a student of statistics ,but my favorite is site designing because of PHP.
     
    lolpasslol, Jul 21, 2012 IP
  6. BRUm

    BRUm Well-Known Member

    Messages:
    3,086
    Likes Received:
    61
    Best Answers:
    1
    Trophy Points:
    100
    #6
    PHP is a server side language, what does it have to do with design? Surely you mean CSS, HTML or Javascript?
     
    BRUm, Jul 21, 2012 IP
  7. christoph

    christoph Active Member

    Messages:
    279
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    55
    #7
    Dude, I can't thank you enough for your help.

    That made complete sense and I have now completed my script too (first ever!!). I think I also understand specifically why the programmer had to use the single cell value (and thus need to use the "serialize" function), because its stored in a generic table that has lots of different config setting values in. Therefore, if someone removes the plugin and installs it again, it retains the coupon code data. (I may be wrong, but it seems a logical reason for doing that).

    It was an issue for me that the code was actually the name of each sub-array initially (which as you said is generally a really bad idea). This is because the code itself is one of the variables I wanted to extract and echo. After a bit of google I found the "foreach" function and managed to organise the sub arrays by "amount" instead (as for my random coupon code generator, this will be constant (the shop owner always wants to have a 15, 25 and 45% off code specifically for the generator)).

    Therefore after the array changed to look like below, I can create variables of the code and expiry date based on %off (amount). It also means if he creates any other coupon codes, they wont get used in the random coupon code generator if they are not 15, 25 or 45% off. End result: happy owner with dynamic code generator and I learned a great deal.

    Thanks for your time dude. Here is the end result that will go into the sale email script: http://i13posefactory.com/chris-support.php (give it a few refreshes)

    [15OFFTEST] => Array
    (
     => 15OFFTEST
                [amount] => 15
                [type] => percent
                [products] => Array
                    (
                    )
    
                [date_from] => 1342742400
                [date_to] => 1343260799
                [individual_use] => yes
            )
    
        [25OFFTEST] => Array
            (
                [code] => 25OFFTEST
                [amount] => 25
                [type] => percent
                [products] => Array
                    (
                    )
    
                [date_from] => 1342742400
                [date_to] => 1343260799
                [individual_use] => yes
            )
    
        [45OFFTEST] => Array
            (
                [code] => 45OFFTEST
                [amount] => 45
                [type] => percent
                [products] => Array
                    (
                    )
    
                [date_from] => 1342742400
                [date_to] => 1343260799
                [individual_use] => yes
            )
    
        [15] => Array
            (
                [0] => Array
                    (
                        [code] => 15OFFTEST
                        [amount] => 15
                        [type] => percent
                        [products] => Array
                            (
                            )
    
                        [date_from] => 1342742400
                        [date_to] => 1343260799
                        [individual_use] => yes
                    )
    
            )
    
        [25] => Array
            (
                [0] => Array
                    (
                        [code] => 25OFFTEST
                        [amount] => 25
                        [type] => percent
                        [products] => Array
                            (
                            )
    
                        [date_from] => 1342742400
                        [date_to] => 1343260799
                        [individual_use] => yes
                    )
    
            )
    
        [45] => Array
            (
                [0] => Array
                    (
                        [code] => 45OFFTEST
                        [amount] => 45
                        [type] => percent
                        [products] => Array
                            (
                            )
    
                        [date_from] => 1342742400
                        [date_to] => 1343260799
                        [individual_use] => yes
                    )
    
            )
    [/COLOR]
    Code (markup):
     
    christoph, Jul 21, 2012 IP
  8. BRUm

    BRUm Well-Known Member

    Messages:
    3,086
    Likes Received:
    61
    Best Answers:
    1
    Trophy Points:
    100
    #8
    No problem mate. I'm glad I could be of help. I remember how difficult it was when I first started programming.

    I had a look at the site in your sig. it's very nice. You're in Cambridge right? Nice to see a fellow Englishman around. I'm up in East Yorkshire.

    Good luck with everything in the future! If you need any further help, feel free to shoot me a PM.

    Lee.
     
    BRUm, Jul 21, 2012 IP
  9. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #9
    Some advice since you're just starting out:

    1) Avoid creating variables for things you only need once.

    2) Avoid saying the same thing over and over again, it consumes memory for no reason.

    3) Avoid checking the same value more than once if you don't have to or if it's value is already determined...

    4) Avoid creating a massive array of 30+ elements just to check if a value is inside a certain range.

    5) A lot of php dev's have their heads up their arses about this, but it's common sense that if you aren't using inline string parsing for variables, use single quotes instead of doubles, they are 5% faster since they don't have to check for as many possibilities.

    6) likewise when using echo, use comma delimits instead of string additions when possible-- additions use more memory and can have unexpected results if you don't understand the difference.

    7) you have three values of roughly equal chance of success -- so why the 1..100 range?

    Just to show you what I mean, this:
    
    	$savings=array(15,25,45);
    	$savingsKey=rand(0,2);
    	$savingsDate='07/30/2012';
    	
    	echo
    		$thankyou,'
    		',$savings[$savingsKey],'0FFE, which will give you a
    		',$savings[$savingsKey],' discount on your next purchase!
    		The code will be active to use next Friday (',
    		$savingsDate,') for 1 day only. Enjoy.'; 
    
    Code (markup):
    Is functionally identical to your original post... and at a fraction the code and less logic flow is far, far faster.

    Though a better version would probably use strtotime and "next friday" to auto-calculate that date instead of hard coding it.
    
    	$savings=array(15,25,45);
    	$savingsKey=rand(0,2);
    	$dateSaving=date('l (j M Y)',strtotime('next Friday'));
    	
    	echo $thankyou,'
    		',$savings[$savingsKey],'0FFE, which will give you a
    		',$savings[$savingsKey],' discount on your next purchase!
    		The code will be active to use next',$dateSaving,' for 1 day only. Enjoy.'; 
    
    Code (markup):
    Will automatically plug in the next friday.
     
    Last edited: Jul 21, 2012
    deathshadow, Jul 21, 2012 IP