Thursday, 8 November 2012

A PHP Class/Object to make html tables

A PHP Class/Object to make html tables

I have been working on a project recently that had cause for a lot of tables to be generated from PHP looking up a database.  After the first couple I got somewhat bored of the amount of time and typing that each table was taking to manualy code on each page.  So I knocked up this little class/object to generate the tables for me, saving me a load of typing in the long run.  I have commented it at the top for usage and stuff, but it's not standards complient, it's just something I put together quick to save me some time, and thought I would share with you all in case you find it helpfull too.

If you need anything explained, or have a suggestion for additions to it, just leave a comment.

p.s. If you lift the code, I'd appreciate if you left a comment for that too ;)

class makeHTMLTable{
/*~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#
Class for dynamicly rendering HTML Tables from nothing more than a single
dataset.

USAGE :-
call something like $table = new makeHTMLTable($myDataset) in your code
where $myDataset is a valid dataset array.
This can be the result of a database query / xml array / dom array / any array
as long as it is a multidimensional, associative array in the form of

array([0]=>array([heading1]=>'value1-1', [heading2]=>'value1-2',....),
array([1]=>array([heading1]=>'value2-1', [heading2]=>'value2-2',....),
...)

you can then call either
$tableOut = $table->newBasicTable($id[string], $class[string], $style[string])
or
$tableOut = $table->newSplitSumTable($split[string], $sum[array], $class[string], $style[string])

newBasicTable :- when calling this method you have the option to pass in three
peices of string information to be applied to the table that is created.
$id will be set as the DOM_id of the table
$class will apply the DOM_class entered to the table
$style applys inline CSS to the table.

all three of these are completly optional and may be left out.
e.g. with no data passed in :-
$tblOut = $tbl->newBasicTable();
this will simply produce
"<table>"

e.g. with extra data :-
$tblOut = $tbl->newBasicTable("myTbl1','content ui-table-widget','color:blue;');
this will produce
"<table id='myTb1' class='content ui-table-widget' style='color:blue;'"


newSplitSumTable :- when calling this class you must pass in the first two
paramaters ($split[string], $sum[array]). $class and $style are exactly the same
as in the newBasicTable, but as this method outputs multiple tables $id has been
dropped.
$split should be the string value that is exactly equal to the heading of the
column that you want to split the data on. $sum should be a simple number key
array of string values that exactly match the headings of the columns that you
want summed.  This sums the values, it does not count the records. As well as
summing each split, there is also an overall total produced at the end.  This
type of table is handy for analysis, such as checking sales by area or duration
 of support tickets by assigned group.

e.g.
$tblOut = $tbl->newSplitSumTable('Sales Area', array('Monthly Turnover','Units Sold', '% To Proffit'));

This will produce a series of tables, one for each sales area, and have a group
totals table after each with the sum per area of the turnover, units and profit
as well as an overall total for everything at the very end.

Additionaly, when the class is created it strips out the heading information,
storing it in $headers.  This can be used for making lists for splitSum tables
so you don't need to depend on user input for the column headers. The data is
also held indipendant of the column headers, so can be manipulated indipendantly.
The class also maintains a "master" copy of the dataset passed to it, so it can
be re-used without needing aditional querys on the datasource.
As well as this the row count and column count are stored, this can be used to
help with pagination, display and further calculations.

$tbl = new makeHTMLTable($dataset);
$headerArray = $tbl->headers;
$dataArray = $tbl->data;
$orginalData = $tbl->dataset;
$rowCount = $tbl->rows;
$columnCount = $tbl->cols;

--added newSplitCountTable()
This works exactly like the newSplitSumTable() but counts the records returned
rather than adding the values.  

~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#*/
    public $headers;
    public $data;
    public $cols;
    public $rows;
    public $dataset;
   
    public function __construct($dataset){
        $this->dataset = $dataset;
        $this->headers = $this->getHeadings();
        $this->cols = count($this->headers);
        $this->rows = count($this->dataset);
        $this->data = $this->getValues();
    }
   
    public function getHeadings(){
        $first = true;
        $results = $this->dataset;
        foreach($results as $record){
            if($first === true){
                foreach($record as $heading=>$value){
                    $headings[] = $heading;   
                }
            $first = false;
            }
        }
        return $headings;
    }
   
    public function getValues($visible=null, $start=0){
        if($visible===null){
            $visible = $this->rows;
        }
        if(($start+$visible) > $this->rows){
            $visible = $this->recCount - $start;
        }
        $dispCount = 0;
        $headArray = $this->headers;
        for ($disp=$start;$disp<($start+$visible);$disp++) {
            foreach($headArray as $valueHeading){
                $values[$dispCount][] = $this->dataset[$disp][$valueHeading];
            }
            $dispCount++;     
        }
        return $values;
    }
   
    public function newBasicTable($id="", $class="", $style=""){
        $meta = "";
        if($id != "") {$meta .= " id=\"{$id}\"";}
        if($class != "") {$meta .= " class=\"{$class}\"";}
        if($style != "") {$meta .= " style=\"${style}\"";}
        $table = "<table{$meta}><tr>";
        foreach($this->headers as $hk=>$hv){
            $table .= "<th>$hv</th>";
        }
        $table .= "</tr>";
        $end = $this->rows-1;
        for($counter=0;$counter<=$end;$counter++){
            $table .= "<tr>";
            $subData = $this->data[$counter];
            foreach($subData as $dk => $dv){
                $table .= "<td>$dv</td>";
            }
            $table .= "</tr>";
        }
        $table .= "</table>";
        return $table;
    }
   
    public function newSplitSumTable($splitField, $sumOnColumns, $class="", $style=""){
        $return = "";
        $subSum = array();
        $totSum = array();
        $meta = "";
        $splitIDX = array_search($splitField, $this->headers);
        if($class != "") {$meta .= " class=\"{$class}\"";}
        if($style != "") {$meta .= " style=\"${style}\"";}
        $sumColCount = count($sumOnColumns)-1;
        foreach($sumOnColumns as $colName){
            $colNameIDX[$colName] = array_search($colName, $this->headers);
            $subSum[$colName] = 0;
            $totSum[$colName] = 0;
            for($i=0;$i<=$this->cols-1;$i++){
                $headings[$i] = $this->headers[$i];
            }
        }
        $colValIDX = array_flip($colNameIDX);
        foreach($colValIDX as $sumByVal => $colName){
            $subSumV[$sumByVal] = 0.00    ;
        }       
        foreach($this->data as $rows){
            $temp[] = $rows[$splitIDX];
        }
        $temp = array_unique($temp);
        foreach($temp as $uselessKey=>$splitVal){
            $splitList[] = $splitVal;
        }   
        $splitCount = count($temp)-1;
        for($i=0;$i<=$splitCount;$i++){
            foreach($this->data as $noGroup){
                if($noGroup[$splitIDX] == $splitList[$i]){
                    $group[$i][]= $noGroup;
                }
            }
        }
        for($i=0;$i<=$splitCount;$i++){
            $return .= "<h2>{$splitList[$i]}</h2>";
            $return .= "<table {$meta}>\n";
            $return .= "<tr>";
            foreach($this->headers as $heading){
                $return .= "<th>{$heading}</th>";
            }
            $return .= "</tr>\n <tr>";
            foreach($group[$i] as $split){
                foreach($split as $key => $value){
                    $return .= "<td>{$value}</td>";
                    $colNo = array_search($key, $colNameIDX);
                    if($colNo){
                        $strToRemove = array("&pound;", ",");
                        $add = (float)$subSum[$colNo] + str_replace($strToRemove, "", $value);
                        $addT = (float)$totSum[$colNo] + str_replace($strToRemove, "", $value);
                        $subSum[$colNo] = $add;
                        $totSum[$colNo] = $addT;
                    }
                }
                $return .="</tr> \n";
            }
            $return .= "</tr>\n </table> \n ";
            $return .= "<h3>Group Totals</h3> ";
            $return .= " <table".$meta."><tr> ";
            foreach ($colValIDX as $h){
                $return .= "<th>{$h}</th>";
            }
            $return .= "</tr>\n <tr>";
            foreach ($subSum as $subKey => $subVal){
                    $subVal = number_format($subVal,2,".",",");
                    $return .= "<td>{$subVal}</td>";
            }
            $return .= "</tr>\n </table> \n <br /> \n <br /> \n";
            foreach($sumOnColumns as $colName){
                $subSum[$colName] = 0;
            }
        }
        $return .= "</tr>\n </table>\n";
        $return .= "<h3>Overall Totals</h3>";
        $return .= "<table{$meta}><tr>";
        foreach ($colValIDX as $oh){
            $return .= "<th>{$oh}</th>";
        }
        $return .= "</tr>\n <tr>";
        foreach ($totSum as $totKey => $totVal){
          $totVal = number_format($totVal,2,".",",");
           $return .= "<td>{$totVal}</td>";
        }
        $return .= "</tr> \n </table> \n";
    return $return;
    }
 
      public function newSplitCountTable($splitField, $countOnColumns, $class="", $style=""){
        $return = "";
        $subSum = array();
        $totSum = array();
        $meta = "";
        $splitIDX = array_search($splitField, $this->headers);
        if($class != "") {$meta .= " class=\"{$class}\"";}
        if($style != "") {$meta .= " style=\"${style}\"";}
        $sumColCount = count($countOnColumns)-1;
        foreach($countOnColumns as $colName){
            $colNameIDX[$colName] = array_search($colName, $this->headers);
            $subSum[$colName] = 0;
            $totSum[$colName] = 0;
            for($i=0;$i<=$this->cols-1;$i++){
                $headings[$i] = $this->headers[$i];
            }
        }
        $colValIDX = array_flip($colNameIDX);
        foreach($colValIDX as $sumByVal => $colName){
            $subSumV[$sumByVal] = 0    ;
        }       
        foreach($this->data as $rows){
            $temp[] = $rows[$splitIDX];
        }
        $temp = array_unique($temp);
        foreach($temp as $uselessKey=>$splitVal){
            $splitList[] = $splitVal;
        }   
        $splitCount = count($temp)-1;
        for($i=0;$i<=$splitCount;$i++){
            foreach($this->data as $noGroup){
                if($noGroup[$splitIDX] == $splitList[$i]){
                    $group[$i][]= $noGroup;
                }
            }
        }
        for($i=0;$i<=$splitCount;$i++){
            $return .= "<h2>{$splitList[$i]}</h2>";
            $return .= "<table{$meta}>\n";
            $return .= "<tr>";
            foreach($this->headers as $heading){
                $return .= "<th>{$heading}</th>";
            }
            $return .= "</tr>\n <tr>";
            foreach($group[$i] as $split){
                foreach($split as $key => $value){
                    $return .= "<td>{$value}</td>";
                    $colNo = array_search($key, $colNameIDX);
                    if($colNo){
                        $strToRemove = array("&pound;", ",");
                        $add = $subSum[$colNo]+1;
                        $addT = $totSum[$colNo]+1;
                        $subSum[$colNo] = $add;
                        $totSum[$colNo] = $addT;
                    }
                }
                $return .="</tr> \n";
            }
            $return .= "</tr>\n </table> \n ";
            $return .= "<h3>Group Totals</h3> ";
            $return .= " <table".$meta."><tr> ";
            foreach ($colValIDX as $h){
                $return .= "<th>Count Of {$h}</th>";
            }
            $return .= "</tr>\n <tr>";
            foreach ($subSum as $subKey => $subVal){
                    $subVal = number_format($subVal,0,".",",");
                    $return .= "<td>{$subVal}</td>";
            }
            $return .= "</tr>\n </table> \n <br /> \n <br /> \n";
            foreach($countOnColumns as $colName){
                $subSum[$colName] = 0;
            }
        }
        $return .= "</tr>\n </table>\n";
        $return .= "<h3>Overall Totals</h3>";
        $return .= "<table{$meta}><tr>";
        foreach ($colValIDX as $oh){
            $return .= "<th>Count Of {$oh}</th>";
        }
        $return .= "</tr>\n <tr>";
        foreach ($totSum as $totKey => $totVal){
          $totVal = number_format($totVal,0,".",",");
           $return .= "<td>{$totVal}</td>";
        }
        $return .= "</tr> \n </table> \n";
    return $return;
    }   
}

Thursday, 1 November 2012

PHP Classes - A Simple Sample Class

PHP Classes - A Simple Sample Class


OK, so in the last two posts we covered the basic theory of objects. Now lets go ahead and make one.

To create an object in PHP we use the term "class" in the same way we would use "function". 
So what can we make an object for? Well pretty much anything really.  To keep it simple at the start we'll go through making an object that simply manipulates some text.

So lets make our object, I'm going to be calling it "myText"

<?php
class myText{

}
?>

There, that was easy enough.  Note that unlike functions there are no parenthesis after the name of the class that you can pass variables into.  We'll come back to that later on.  Now we'll add the first method.  The first thing we are going to need to do is get the text that we will be formatting, so lets create a method that will do that, this one I'll be calling "getText".

<?php
class myText{

 public function getText($textIn){
 
 }
}
?>

Hmmm....hang on, what are we going to be doing with this text after we get it?  Well the idea is that we can search the text for occurences of the word that we choose once it's loaded into the object.  So any method could need to access the text.  Guess we had better stick in an object level variable - these are actualy called paramters, but for now I'm going to keep calling them variables -  to keep the text in so that all the other methods will have access to it and then have the getText method send the text it gets out to this variable.

<?php
class myText{
 public $text;

 public function getText($textIn){
  $this->text = $textIn;
 }
}
?>

OK, so that's that done.  See the use of $this->text ? when working anywhere inside a class $this is basically a short way of saying "This Class" or "This Object".  the use of -> is saying which variable or method within the class or object to are referring to.  Also note that the $ is dropped from any variables that come after the -> (but you still need to use the parenthesis at the end of function names). So $this->text=$textIn tells the method that it is going to take the contents of the $textIn variable and send them to class variable $text.  You will also have by now (I hope) noticed the word public at the start of both the $text variable and the getText() function.  These are here to explicitly define the scope of each of these.

Right, so we have a method of getting text into the object now.  Let us now make a method that will do something to that text.

<?php
class myFormat(){
 public $text;

 public function getText($textIn){
  $this->text = $textIn;
 }

 public function makeCaps(){
  $this->text = strtoupper($this->text);
 }
}
?>

So now we have a method that will make all the text uppercase. Not exactly anything to write home about, but it at least lets us see how easy it is to address variables that are stored at the object level from within a method.

Let's blast on and add a couple more methods to play about with the text, we'll take a look at them once we're done adding them all.

<?php
class myText{
public $text;

  public function getText($textIn){
    $this->text = $textIn;
  }
 
  public function makeCaps(){
    $this->text = strtoupper($this->text);
  }
 
  public function delimit(){
    $delimitText = $this->text;
    $delimitText = str_replace(".", "", $delimitText);
    $delimitText = str_replace(",", "", $delimitText);
    $delimitText = str_replace("\n", '|', $delimitText);
    $delimitText = str_replace(' ', ',', $delimitText);
    return $delimitText;
  }
 
  public function txtToArray(){
    $txtForArray = $this->delimit();
    $textArray = explode('|', $txtForArray);
    for($i=0; $i<=count($textArray)-1; $i++){
      $textValue = $textArray[$i];
      $textBack = explode(',', $textValue);
      $textArray[$i] = array_filter($textBack);
    }
    return $textArray;
  }
 
  public function findWord($word){
    $haystack = $this->txtToArray();
    for($i=0; $i<=count($haystack)-1; $i++){
      $result = array_search($word, $haystack[$i]);
      if($result != false){
        $line = $i+1;
        $wordNo = $result+1;
        $return[] = "Line No $line, Word No $wordNo";
      }
    }
    return $return;
  }
}?>

OK, so that's a whole bunch of code that you may or may not fully understand.  Suffice it to say we have just added some methods that take in a text string, strips all full stops and commas out of it, splits the text ito lines (using the linux/unix \n control character, if you want to work with windows controls change the str_replace("\n"... to str_replace("\n\r"... ) and words and then lets someone find a word in the text returning each location by line and then number of words along that line that the number is in.  Look over the delimit() and txtToArray() methods and you will see that they are very similar to the normal functions you would write outside of a class/object.  they take in values and return other values and you can even call one method from inside another.

So now that we have made our class it would be good to get some output from it.  Lets drop down outside the closing } of the class and add the code to make the class do something.

...
}
$mySearch = new myText();
$mySearch -> getText("This is some sample Text\nUsed to test out our sample class.");
$searchResults = $mySearch->findWord("sample");
if(count($searchResults) >= 1){
echo "word \"sample\" found at the following locations:<br>";
}
foreach($searchResults as $result){
echo "$result <br>";
}
echo"<br>Within : <br>{$mySearch->text}";

?>

Notice that there is still the parenthesis when you call a new class, even though we didn't use any to declare the class at the beginning? Remember how I said we would come back to that? well here we go.

Classes have special methods, one of the most important is the constructor.  This lets the class gather everything it needs when it is created.  Lets modify our class a little bit and add the following constructor method at the top :

<?php
class myText{
public $text;

  public function __construct($text){
    $this->getText($text);
  }

  public function getText($textIn){
....

OK, now we have a constructor in place, what this does is load the text into the object as it's created.  This makes sense in the example here because the object depends on having sent into it for it to really do anything. now when we create the new object we add the text into the parenthesis there, and skip the line that calls the getText method altogether.

...
}
$mySearch = new myText("This is some sample Text\nUsed to test out our sample class.");
$searchResults = $mySearch->findWord("sample");
if(count($searchResults) >= 1){
echo "word \"sample\" found at the following locations:<br>";
}
foreach($searchResults as $result){
echo "$result <br>";
}
echo"<br>Within : <br>{$mySearch->text}";

?>

That's almost it for our first look at classes, just one more thing, the scope.  So far we have made everything public, this is the best way to create a new object because it lets you access each of the methods and variables for debugging.  Now we have finished it, we can change some of the scope.  For methods and variables that you don't want anything outside the object to access you can set it to either protected or private.  Private goes a step further and stops child objects and/or parent objects accessing the method/variable either.  Again it's not something we'll be getting into here, but for the sake of an example, change the word public that is before the $text at the top of the class to protected and see what happens when you run the code again.
Not good, huh? It stops the code getting direct access to the variable inside the object, so lets change that back.  Where protected would come in handy would be to use it for the delimit() and txtToArray() methods, this would stop anyone calling these methods directly and potentially using them out of context.

Anyways, that's it for this "beginner class" (pun intended).  I suggest that, assuming I didn't confuse you too much, you look into patterns in PHP. These are guides to standard designs for creating your own objects.

Tuesday, 30 October 2012

PHP Classes - What is an Object?

So What Is An Object?

This isn't an easy a question to answer, and I am sure by the time I am done I will have you wishing you never asked, but you did so here it is, and as I have just renewed my membership to the "Analogies Fan Club" I'm going to make use of a rather drawn out analogy to help me with this.
For this analogy I am going to assume that you live in a house, know someone that lives in a house, or have at least had a walk about inside a house.  As I hope you will all agree, a house is an object (in the physical world at least).  Well lets take that and make it an object in the programming sense.  A house has one or more rooms.  These rooms, when transconceptionalized (yes, I just made that up) into the programming sense become methods.  So taking a general 2 bedroom house with lounge, kitchen and bathroom gives us an object called house with methods called lounge(), kitchen(), bathroom(), bedroom1(), and bedroom2().

Right, so that was easy enough.  Now to deal a little bit with "Scope". Scope is the term used to describe how visible a method or a variable is.  You can have variables within the root of the object as well as within each of the methods.  And just like rooms in a house variables of the same name that are in different rooms are kept apart from each other. so if you have a variable called TV in lounge() and a variable called TV in bedroom1() anyone who comes to the house to watch TV can be sent to either of these rooms either by you or by knowing when they arrive, if you made the TV variables public, which room is showing the show that they want to see.  So that's variables within the methods touched on, now for the variables in the root of the object.  These variables are generally used to describe the object, or to hold the information withn the object that isn't specific to the methods.  So a house could have variables that state the people who live there, the amount of electricity gas and water the house uses, phone line information, how many times there has been a delivery to the house by a courier and what the courier company was.  These do not need to include variables for things within methods that can or often do pass into other methods.  So for example you do not need to have an object level variable called "$dadsCoffeeCupLocation" to track the movements of said sacred artefact around the methods of the house. each method can relate directly to any other method within the object and pass information that way.  What's more, a method can also be an activity that goes on in the house, as well as the room in which it happens.  So you could have a tracking method that is dedicated to the task of keeping track of "$dadsCoffeeCup" as it is passed between each room method.

So, starting to sound more than slightly complicated?  Believe it or not, it's actually a good thing if it is.  Objects are simple on the outside and complicated on the inside.  This means that, once you have coded the complex stuff once at the start, it's really dead simple to access the stuff that the object contains. 

PHP Classes - What is OOP?

What is OOP?


So, OOP. What is it and why is it so good? OOP, or Object Oriented Programming, is the term given to programing languages that either let you, or insist that you, program the code using general objects to create the processes that the program will perform.

Not too helpful huh?  OK, lets take a step back for a moment.

Some History

In the beginning (well not the beginning, as in 1843 Ada Lovelace beginning, more kind of late 1950's - 1960's type beginning) there was Assembly Code (there actually still is assembly code, it's just that these days it's something of a social recluse). Assembly Code is about as close as telling the computer exactly what to do as someone with higher language skills would ever want to get.  This language had no procedures, no functions (per say), no classes and no modules.  This meant that as the number of programmes working on any given project increased - so did the complexity of keeping the overall code intact.  As each programmer worked on a specific piece of code that had to interact flawlessly with every other piece of code.
As far as Assembly Code went that was manageable, because the language is low level, the commands that the language accept are pretty limited.  However, people got to thinking "there has to be a better way to do that", and (thankfully for the rest of us) they were indeed right.  Other Languages started being developed that were designed to act as a translator between the way the brain works and the assembly code used to make the program work.  And so the evolution of programming languages had truly begun (it was actually begun in the 1940's, during the second world war, by a very clever German gent called Konrad Zuse, but that's a different level of evolution).
So as things progressed languages got more and more "human friendly".  Part of this happening was alterations to how people programed.  The big step was the arrival of Procedural Programming.  This allowed programmers to write complex subroutines once within the program and call them for re-use as and when needed.  It also meant that a group of programmes could write independent procedures for the same program and  these procedures could be incorporated into the overall program in a much more modular way, allowing for much smoother integration of code into the overall program.  Procedural programming was great.  At the time. Now its been relegated to the standing of only "Damn Good" and title of Great has been taken by the Object Oriented kid from three doors down.

Now To The Point

Object Oriented programming took Procedural programming and pimped it up.  Procedures became known as Methods within the objects known as Classes.  Instead of having a whole list of procedures loaded at the start of the program now you can have a whole bunch of objects that are only loaded when they are used by the program.  These objects can also be stored in a library and are generally easier to organise than the Dewey Decimal System.

So What's This To Do With PHP Then?

Well PHP is an object oriented language.  However, it's not strictly an object oriented language.  What that means that one of the things that makes PHP so much fun to use and what makes PHP so easy to pick up, is that it is what's called a "loose language".  This means that it isn't strict about how you program in it, as long as PHP can make sense of the logical steps you have used to write the program then you will get away with it.  Other languages aren't quite so relaxed about how you code - Java by SUN/Oracle for example will have no hesitation in throwing the toys not only out the pram, but squarely at your face if you try and code without using objects.  Yes choice is good, but then again, so are rules.  PHP's loose nature can, and very often does, cut both ways.





Friday, 11 May 2012

PHP - Where To Start - Part2 - Getting It On The Screen

OK, so in Part1 we got to grips with basic operators.  But we have nothing to show for blood and sweat.  Let's remidy that.

There are a few ways to get PHP to display to the screen, and while they may apear on the surface to all do pretty much the same thing, they are all different and all there for a reason. In no perticular order here are two of the most common methods:

echo
print

As well as those, there are other commands for more precise displaying of information, but they arn't related to this level of coding. It's as well noting just now that there is a big difference in the way that the PHP processor handles single quotes ( ' ) and double quotes ( " ).  I will ilustrate this difference in the code section for this page.  If you recall, in Part1 there was a line at the end of the code section that started with the following on it:
//EOF...
On the line just above that add the following code using copy and paste, and then save and view the page in your browser, as coverd in Part 0.1

PHP - Where To Start - Part 0.1 - Genesis

In The Beginning there was only darkness...Then the power came on and someone thought it would be cool to have a scripting language that ran on the server side but was still processed from within the web server it's self, without needing to run off and buy some application resources from a service down the street that it didn't really get on with in the first place.

PHP is that scripting language.  It stands for (rather puzzlingly) Hypertext PreProcessor, however it was originally coined as (somewhat more understandably) Personal Home Page. The guy that had the thought that it would be cool also had the thought that it would be way better if it was free for people like you and me to play around with (just like your mum's cleaning products were when you were playing at making explosives). His name was Rasmus Lerdorf and he single handedly wrote the first two versions of PHP.

And so we have PHP, accessible to all.  Whole communities have even been built around it's humble foundations.  It's impact on the web is immeasurable. And now were going to cover the basics.

This is an analogous description of the fundamental information about PHP.  It's not meant to be taken as a gospel truth, but rather its meant to help get some key concepts to stick so you can get on with the fun stuff.  

PHP is, as I said in that nonsense at the start, a scripting language.  This means that it does not require a compiler to run, it just shoots down each line of the code as if running the hurdles.  It's very lite, and apart from the PHP software it's self, and a web server software, you don't need any special toys to make it come out to play.

If you are running windows, the best way to get from nothing to a working php setup is (in my all devouring opinion) to go download XAMPP from www.apachefriends.org and install it.  I suggest installing it to c:\xampp, but where you put it is your call, just know that you are going to want to get into that folder a lot. One important thing I will say is not to use ANY spacial characters in the path name, so no ~'s or #'s or anything like that. This isn't an issue for the PHP side of things, it is however a huge problem if you every want to use the PEAR application.

Once you have a working environment you will need something to make your php pages with.  This bit's as easy or as hard as you want to make it.  You can simply use notepad (NOT wordpad - notepad, they are different) but this will give you no visual aid when coding.  You can download for free a coding specific text editor like pspad, notepad++ or any number of other alternatives.  You can download, again for free, the eclipse IDE for java and then download the PHP Language add on.  Or you can spend some money and buy an IDE such as Dreamweaver or Zend Studio Pro (I actually do not recommend the use of an IDE for someone who is just beginning, they have a lot more in them - especially Zend Studio - than you will use at this level, and the extras make getting confused a lot easier).

After you have settled on your application you're almost ready to get on and make your first php page.  Open up your program and choose new file (as I have no idea what program your likely to be using your going to have to work out this complication on your own).  You want to then go immediately to Save As... and navigate to where your web root is.  If your using XAMPP that will be in the directory that you installed XAMPP to and then into the directory called "htdocs".  Once there save the page as "index.php" making sure that, if the program supports it, you have selected the extension type as php and if the program doesn't support php file extensions you select "all files" as the file type.

Now you have, in effect, created your first php page.  How'd that feel? crap? really? Yeah I get where your coming from, but let's be fair, if I told you to put the 3 lines of code in the file that would have had show "hello world" you wouldn't have felt any better about it, would you? especially as I haven't gone over how to actually view the fruits of your coding loins.

First we need to make sure that the web server is running, so in XAMPP (if your not using XAMPP I'm gonna assume you went that road because you know what your doing, and I'll will leave you do your thang) You want to launch the XAMPP Control Panel, either from the start menu, or from the desktop shortcut (sometimes on Windows 7 you will get a message about this thing must be run from someplace that your sure is where it was just run from, you can normally just ignore that and click whatever button it presents you with).  In the control panel have a look at the list under Modules, the top option should be Apache.  If this has a green "Running" beside it, your all good, if not click the "Start" button and watch the white box.  you should have the Running message displayed in a few moments.  OK, so now were running a web server.  This is important, because your PHP pages need to viewed through the web server to be processed. So if you want to view your PHP page, it's pointless going to C:\xampp\htdocs\index.php because that's just going to show you the raw code. What you need to do (This Is VERY Important!) is open up your Internet browser and then find the address bar.  In there change the content to be http://localhost/index.php and there you can see your page.  It's blank just now, but as we move through sections we'll get to that.

One final, impossible to progress without knowing, thing before we drop into the coding of our very own super-fantastic PHP pages, EVERY PHP Page MUST have
<?php
at the start and
?> 
at the end. This is what tells the web server "process my damn code fool" and without them, everything will go horribly horribly wrong.

Right, on to Part 1 then...

PHP - Where to start? - Part1 Operators

So, your new to PHP and programming in general.  You're also not a season ticket holder for your local book reading club.  But you do want to learn some PHP for whatever reason.  And that's where the inevitable question comes from : "Where do I start?"

Until I made this post and can now, in complete arrogance, turn round and provide the answer of "Here", this was not as easy a question to answer as "where not to start".  Lets face it no one really looks up a "how to code" book or site to have the first portion of the book/site send you to sleep with the history of the language and the principle ideals of OOP.  As important as these things are that's not what your here to learn, so lets move swiftly on.

Each time I'm asked "where should I start" I always reply with "operators".  It's kind of like trying to learn mathematics, you need to know what +, -, /, *, = and all the rest, all mean before even the simplest tasks make sense. The way I like to look at the main operators for beginning PHP is to split them into three category's : alteration, comparison and assignment - these are other 'official' classifications, and .  Alteration operators change the value of something depending on what the original value was, these are the familiar
+       -       *       /
operators, but there are also ++ and -- operators.  these increment (increase by 1) and decrement (decrease by 1).

Comparison operators are used when we need to check the value of something against certain criteria. these operators are :
<   ~~Less Than
 >  ~~Greater Than
>=  ~~Greater Than OR Equal To
<=  ~~Less Than OR Equal To
== (yes it's meant to be 2 of them)  ~~Equal To
and === (again, that's meant to be 3 of them).  ~~Identical To
All of the operators above can be prefixed with ! to make it NOT, so !< would be NOT Less Than, or  whichever operator you are using.  I say "all" but actually, when using ! with == or === you don't just add it to the left of them, you actually replace the first = with the !, so:
!=    ~~NOT Equal To  - and -
!==  ~~NOT Identical To
The times that you make use of <= and >= you need to be careful and put them in that order, changing the order changes the operator.  you also need to be careful (and this one is tricky) to get out of the habit of using a single = to check if one value equals another.

Assignment Operators are a bit shorter.  Here at the beginning we are only going to look at one of them :
=
this assigns the value that is on the right of the operator to whatever is on the left of it.

OK, so lets get some code up already so we can see these operators in their natural habitat.



Right, so you seen that rouge operator in there? that's one of PHP's handiest shorthand operators, it's a concatenation operator.  This means that instead of just replacing the contents of the variable on the left of it, it appends the value on the right onto the end of it.  This only works if the variable has been declared (the line where it is assigned as an empty variable just above the while loop).

So there we have covered the basics of operators, and seen how they work in code.  But if, like me, you have trust issues, and you want to see what's in each of those variables with your own eyes, you'll be wanting to move onto Part 2 - Printing to Screen (just as soon as I post it...).

Wednesday, 11 April 2012

Simple PHP Login Script

Login Scripts for PHP are 10 a penny, so I thought I would fling my own up, since there are still a lot of people out there that have problems with these.  I have set the script up to attach to a MySQL datatbase, though I have left out the details as this will be specific to your setup.  It's designed around my standard basic login table so it uses that table name.  If you already have your own table set up you will need to alter the tablename and probably the field names too in the <<<SQL code block to use your own.  Also, if you do not have a column in your login table that identifies if an account is disabled or not you will need to remove the two lines from the <<<SQL code block that read:
AND
uStatus != 0


As the title says, this is just a simple login script, it's about the bare minimum that you should be using for a multi-user portal.

OK, so what we are doing in the script is as follows:  We open up a php Session, that will carry information accross different pages - this is what tells the rest of the pages on the site that the user is logged in.  We identify the user across these pages by assigning values to session variables on successfull login.
We check our login table to make sure the user is registered in the database.  If there are any requests for a signup script I will post one of those also, but this is just the login only. This script looks for the password to be encrypted using an MD5 one way key, this can be changed to not use encryption (Strongly recomend you don't do that) or to use whatever encryption is set using your signup script.  If it finds a match the user name and password then a simple message is displayed, this can be changed to perform a page redirect or any other action you desire. If the script fails to find a match it shows a message and displays the form again for the end user to have another try.
The script uses only mysql_real_escape_string() for an atempt to sanitise form input, but this is applied in a function that you can easily add other checks to if you want.



Free Hosting



so without any further flapping, here's my sample login script :-


<?php
session_start();

mysql_connect('localhost','root','') or die (mysql_error());
//line above will need to be changed to your MySQL server host, user name and password

mysql_select_db('general');
//line above will need to be changed to your database name (this is NOT your table name)

function makeSafe($varToCheck){
$varToCheck = mysql_real_escape_string($varToCheck);
// this can be used to add other checks to the data to increase sanitization, add as many other lines in the same format as above as you desire.

return $varToCheck;
}

$htmlHead = <<<HTML_HEAD
<!DOCTYPE html>
<html lang="en">
<head><title>Login</title></head>
<body>
HTML_HEAD;

$loginForm = <<<LOGIN_FRM
<form action="" method="POST" id="loginForm" name="loginForm">
<label for="name" form="loginForm">User Name : </label>
<input type="text" id="name" name="name" value="" />
<label for="pass" form="loginForm">Password : </label>
<input type="password" id="pass" name="pass" value="" />
<input type="submit" id="subForm" name="subForm" value="Login!" />
</form>
LOGIN_FRM;

if(!isset($_POST['subForm'])){ // check that the form has not (!) been submitted
echo $htmlHead;  //send html header info to the page
echo $loginForm; //send login form to the page
echo "</body></html>"; // tidy up closing the page
}
else{ // if the form has been filled in and submitted
$safeName = makeSafe($_POST['name']);
$safePass = makeSafe($_POST['pass']); 
//$safePass = md5($safePass);
// the above line uses md5 encryption on the password, you can change this to whatever you use in the registration script to encrypt your users password info.

$sql = <<<SQL
SELECT uID, uLevel
FROM login
WHERE
(
uName = '$safeName'
AND
uPass = '$safePass'
AND
uStatus != 0
)
SQL;

$qry = mysql_query($sql) or die(mysql_error()."<br> when trying to run<br>". $sql);
$num = mysql_num_rows($qry);

if($num != false){ //action to perform on success
$row = mysql_fetch_assoc($qry);
$id = $row['uID'];
$level = $row['uLevel'];
$_SESSION['id'] = $id;
$_SESSION['level'] = $level;
$message = "Congratulations {$_POST['name']} Login Successfull";
echo "$htmlHead $message </body></html>";
}
else{ // action to perform on failure
$message = "<span style=\"color:red\">Login Failed with that username and password. Please Try Again.</span><br>";
echo "$htmlHead $message $loginForm </body></html>";
}
}
?>


!!UPDATE!!
In light of PHP7 removing all support for the mysql_ library I have decided to give this script a much needed update to use PDO. Also, I will include a more secure hashing algorithm than the basic MD5 one that is in the code above. Just remember that the password must be hashed using the same method for both the registration and the login or they won't match in the database!
I am going to leave the old code in place purely as a reference - please do not use it in any new scripts that you are writing.

New script using PDO:
<?php
session_start();

$con = new PDO("mysql:host=localhost;dbname=databaseName","userName", "passwrd");
//line above will need to be changed to your MySQL server host, database name (this is NOT your table name), user name and password

function makePass($word=''){
//function to make password hash
  $dbSalt = '$2a$07$'.substr(hash('whirlpool',$word),0,22);
  $dbPass = crypt($word, $dbSalt);
  return substr($dbPass,12);
}

$htmlHead = <<<HTML_HEAD
<!DOCTYPE html>
<html lang="en">
<head><title>Login</title></head>
<body>
HTML_HEAD;

$loginForm = <<<LOGIN_FRM
  <form action="" method="POST" id="loginForm" name="loginForm">
  <label for="name" form="loginForm">User Name : </label>
  <input type="text" id="name" name="name" value="" />
  <label for="pass" form="loginForm">Password : </label>
  <input type="password" id="pass" name="pass" value="" />
  <input type="submit" id="subForm" name="subForm" value="Login!" />
  </form>
LOGIN_FRM;

if(!isset($_POST['subForm'])){
// check that the form has not been submitted
 echo $htmlHead;
 //send html header info to the page
 echo $loginForm;
//send login form to the page
 echo "</body></html>";
// tidy up closing the page
}
 else{
 // if the form has been filled in and submitted
   $name($_POST['name']);
   $pass = makePass($_POST['pass']);
// the above line uses the custom makePass function to create a secure password hash using two-part one-way encryption
   $sql = <<<SQL
   SELECT uID, uLevel
   FROM login
   WHERE (
     uName = :name
     AND
     uPass = :pwd
     AND uStatus != 0
   )
SQL;
 $stmt = $con->prepare($sql);
 $stmt->bindParam(':name', $name, PDO::PARAM_STR);
 $stmt->bindParam(':pwd', $pass, PDO::PARAM_STR);
 $stmt->execute();
 if($stmt->errorInfo()[0] == 00000){
 //if there are no errors returned:
   $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
 }
 else{
 //if there is an error, display it on the screen - !!THIS SHOULD NOT BE USED IN A PRODUCTION SETTING!!
 print_r($stmt->errorInfo()[3]);
 }
 if(count($result) === 1){
 //action to perform on success
 foreach($result as $row){
 $id = $row['uID'];
 $level = $row['uLevel'];
 $_SESSION['id'] = $id; $_SESSION['level'] = $level;
 $message = "Congratulations {$_POST['name']} Login Successfull";
 echo "$htmlHead $message </body></html>";
 }
 }
 else{
// action to perform on failure
 $message = "<span style=\"color:red\">Login Failed with that username and password. Please Try Again.</span><br>";
 echo "$htmlHead $message $loginForm </body></html>";
 }
}
?>

Monday, 19 March 2012

My PEAR Net_SMTP function for PHP

OK, so some time ago I had an issue that I needed to send multipart/mime email through an authenticated SMTP server.  Had I been using a Linux distro this wouldn't have been a problem, as I could have simply added the authentication information into the relevant .ini files and that would have let the PHP mail()connect and send.  However I am normally coding for Windows environments so needed another solution.  I had a poke about on Google, as you do, and found that there were a fair few third party libraries that were out there, under differing license models, that would do the job.  Nothing was available as an inherent function in PHP.  Resigned that I was going to have to install something new, I opted for the PEAR NetSMTP class. This was because I already had the base components of PEAR installed on the system, so all I had to do was grab the package and its dependencies and away I could go.   And so started a three day fight to get the damn thing to send a mail.

What I found to be of particular detriment to my cause was that there was so little documentation for the class, and in particular its use, that it was a full on trial and error experience.  As a result I had to ask several questions on phpfreaks.com and, with some help on there I got the thing working as I needed it to.  Having spent as long as I did trying to make it all work as I wanted it to, I thought I would create a function for others to use to make life easier for those in a similar position.  So I wrote the following:

<?phprequire_once 'Net/SMTP.php'//stick this line somewhere at the top of your page
/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
I wrote this function to use the PEAR Net_SMTP class as I needed something that
would pass SMTP authentication information, and didn't want to install any new
librarys.  The most important parts of this were getting the right line terminator
and then getting the right number of them for each line!
Feel free to tweek this as much as you like, just don't change any of the line
ends or your fixing it on your own :D
--This is NOT configured to work with SSL or TSL (so no sending through gmail)
Any questions you can get in touch at:
muddyfunster.webdev@gmail.com
*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/

 function sendSMTP($subject$body$user='defaultUserName'$pass='defaultPass'$to='Friendly Name'$destination='default@recipient.ext'$from='Friendly Name'$sender='default@address.ext'$fName=null$attachment=null){ 
//set defaults for user name, password, to, from, sender and recipient here ^^^
$e "\n"; //define end of line 
$bound"==MUDDY_FUNSTER_".md5(time()); //create a unique boundary for this mail to separate each different type in the message.
 @$smtp = new Net_SMTP("your.mailserver.ext"25); // set to youe mail providers A record and port number (IP Addresses will also work for server) 
@$smtp->connect(60); //create connection and set timeout duration 
@$smtp->helo('your_mail_domain.ext'); //start comunication with server --change to your mail providers domain    
@$smtp->auth($user$pass);  //authenticate account 
@$smtp->mailFrom("$sender");  //email address of authenticated account, can set default in function declaration
@$smtp->rcptTo("$destination");   //recipient of mail, can set default in function declaration 
$header "";  //set header as empty 
$header .= "From: $to <$sender>".$e// Set Friendly Name and address of sender
$header .= "To: $from <$destination>".$e// Set Friendly name and address of recipient
$header .= "Subject: $subject".$e;  //Set mail Subject 
$header .= "Reply-To: $sender".$e;  //Set Reply-to address 
$header .= 'MIME-Version:1.0'.$e;   //use MIME transport 
$header .= "Content-type:multipart/mixed;"// Define multipart mail contnent 
$header .= "boundary=\"".$bound."\"".$e.$e//set unique boundary for each different type of content 
$message $header//include headers into message information 
$message .= "--".$bound.$e//open boundary 
$message .= "Content-type:text/html;";  //set contnent as html for mail body
$message .= "charset=\"iso-8859-1\";".$e//set charactor set to be used in mail body - can be changed to suit 
$message .= "Content-disposition:inline;"//use inline to inferr displaying of contnet in the body without need for end user input 
$message .= "Content-transfer-encoding:quoted-printable".$e.$e.$e//set transfer encoding for html text content
$message .= $body.$e.$e//add the contnent of $body which is passed into the function
if($attachment != null && $fName != null){ //check if there is an attchment being passed into the function and that it has a name
$message .= "--".$bound.$e//add boundary to change to next content type
$message .= "Content-type:application/octet-stream;"//set content type to suitable type for attachment (octet-stream is for generic binary data other are available) 
$message .= "name=\"$fName.xml\"".$e//set the file name
 $message .= "Content-disposition:attachment;"//use attachment to infer data that is being passed as a file 
$message .= "filename=\"$fName.ext\";".$e//set the filename and extension as it will be recieved 
$message .= "Content-transfer-encoding:base64".$e.$e// encode the file for transfer
$message .= $attachment.$e.$e// add attachment contents 
} 
$message .= "--$bound--".$e//closing boundary shows it's the last part of the MIME and the mail is now complete 
@$smtp->data($message); //send message to the server 
$msg $smtp->getResponse(); // get server response array format -- $msg = Array([0]=>'server numeric code' [1]=>'Text message from server for code') -- hMailServer success response code is 250.  This can be called after any of the $smtp-> calls for error capture
@$smtp->disconnect(); // close server connection
 return $msg//pass out server response array
 }                     
 //call function using $var = sendSMTP($subject, $body, $user, $pass, $to, $recipientAddress, $from, $senderAddress, $filenameOfAttachment, $attachmentContent);
//$to and $from are the "Friendly Name" values for the message e.g. John Doe
//if you are passing in attachment content you MUST pass in a file name (prefferably with extension, but thats your targets problem) for it as well.

 ?>

The formatting has been a little upset posting the code up like this, so if you have any issues copying it you can find the same code at the end of my thread on phpfreaks.com here.

To use this function you must have PEAR Net_SMTP installed and up to date.  Once that's done just copy this code and save it in either a new .php file and load it using include_once or paste it into your existing include files/current page.

This function lets you send HTML formatted messages with or without an attachment.  The other thing is that it is written to pass in attachments on the fly, so there is no need to have an existing file saved on the server to attach (I wrote it this way as my original code was generating xml file attachments from a database lookup, so I really didn't want a bunch of files littering the server when I already had the information in the database anyway).

You will also see a whole bunch of @ suppressors in the function.  I normally avoid using these, but something in the way the Net_SMTP class accesses the PEAR error handling class keeps throwing warnings, even though there isn't an issue with the actual function or it's coding, it's just the relationship between the SMTP and PEAR error classes that's a bit out.

I have tested this using hMail free mail server and it worked a treat.  The last few lines of comments explain how to call the function in your code and how to read the server response array that the function returns.

Another thing is the function declaration has the option for default values, you will obviously need to change these if you want to use them.  I do feel that I should point out, this sends mail as a fully authorised account on whatever mail server you hook it up to, thus any spam sent from this will be traced to your mail server, not just the script, so you would probably want access controls in place if you choose to use all default values.

Enjoy, and let me know if you have any problems with this.