Web page inputs and insert into database – Part 2

As from here, where I outlined the javascript, html part of the exercised here is the php and mysql parts of the problem.

Here is the table that I created within MySQL

CREATE TABLE `User` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `firstName` VARCHAR(50) DEFAULT NULL,
  `lastName` VARCHAR(50) DEFAULT NULL,
  `email` VARCHAR(50) DEFAULT NULL,
  `phoneNum` VARCHAR(20) DEFAULT NULL,
  `guid` VARCHAR(36) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;

As from my other post about MySQL triggers, so to find out more information about why please check out that page, and here is the trigger that I created for the above table.

CREATE TRIGGER User_insert 
BEFORE INSERT ON USER 
FOR EACH ROW 
BEGIN 
        SET NEW.guid = uuid(); 
END

The reason why I created this for was because within the exercise they asked “would forward planning, i.e. adding a unique code to the user details that could be used to validate their email address”, which by using a uuid, you can use that as a unique code.

so the only part left is the PHP that will connect to the database and also sanitize the inputs within sql insert. So created a class that has a constructor that will open a database connection to a database

      private $dbLink;
      /* connect to the database*/
      function __construct($host = "localhost", $user = "user", $password = "password", $database = "database")
      {
	$this->dbLink = mysql_connect($host, $user, $password);
	if (!$this->dbLink) die("no database present");
	if (!mysql_select_db($database, $this->dbLink))
	  die("no database within the database");
      }

Here I try to sanitize the insert string so that it will use the mysql_real_escape_string, this will use a php function that helps with SQL injections, also I am using the stripslashes and then trim the string to make sure that there is no white spaces (or any valid text left).

      /* santize the input for a mysql database */
      public function santizeInput($theStr)
      {
	return trim(stripslashes(mysql_real_escape_string($theStr)));
      }

and then to insert the data, just use the mysql_query and the sanitize function above to insert data into the database.

      /* insert the data into the database */
      public function insertData($sqlData)
      {
	mysql_query($this->santizeInput($sqlData), $this->dbLink) or die("Error inserting data");
      }

And here is where I get the data from the form post from the web page and then double sanitize the data and then create a database link, which in-turn use to insert the data.

    // could use foreach loop $_POST inputs, but I personally prefer to pick them up.
    $firstname = $_POST['firstname'];
    $secondname =$_POST['secondname'];
    $email = $_POST['email'];
    $phonenumber = $_POST['phonenumber'];
 
    /* could do additional checks on input incase it is sent via backend POST and not via the webpage,  could do with regular expression as well ? */
    $db = new databaseAccess("localhost", "username", "password", "database");
    /* can santize the inputs to make sure that there is some data to "play" with */
    $firstname = $db->santizeInput($firstname);
    $secondname =$db->santizeInput($secondname);
    $email =$db->santizeInput($email);
    $phonenumber = $db->santizeInput($phonenumber);
 
    if (checkLength($firstname) && checkLength($secondname))
    {	
	$sql = "insert into User (firstname, lastname, email, phoneNum) values (\"$firstname\",\"$secondname\",\"$email\", \"$phonenumber\")";
	$db->insertData($sql);
	echo "Data inserted";
    }

I did write within the exercise that since someone may try and post the data to the server within using the webpage (naughty people that they are!!) you could also check the inputs again for there data validity.

Here is the full code for the web page in total.

<?php
    class databaseAccess
    {
      private $dbLink;
      /* connect to the database*/
      function __construct($host = "localhost", $user = "user", $password = "password", $database = "database")
      {
	$this->dbLink = mysql_connect($host, $user, $password);
	if (!$this->dbLink) die("no database present");
	if (!mysql_select_db($database, $this->dbLink))
	  die("no database within the database");
      }
 
      /* disconnect */
      function __destruct()
      {
	if (!$this->dbLink) mysql_close($this->dbLink);
      }
 
      /* santize the input for a mysql database */
      public function santizeInput($theStr)
      {
	return trim(stripslashes(mysql_real_escape_string($theStr)));
      }
 
      /* insert the data into the database */
      public function insertData($sqlData)
      {
	mysql_query($this->santizeInput($sqlData), $this->dbLink) or die("Error inserting data");
      }
    }
 
    function checkLength($theStr)
    {
      if (strlen($theStr) > 0) 
	return true; 
      else 
	return false;
    }
 
    // could use foreach loop $_POST inputs, but I personally prefer to pick them up.
    $firstname = $_POST['firstname'];
    $secondname =$_POST['secondname'];
    $email = $_POST['email'];
    $phonenumber = $_POST['phonenumber'];
 
    /* could do additional checks on input incase it is sent via backend POST and not via the webpage, not sure if SOAP are looking for that as well ? 
      could do with regular expression as well ? */
    $db = new databaseAccess("localhost", "User", "PW", "Test");
    /* can santize the inputs to make sure that there is some data to "play" with */
    $firstname = $db->santizeInput($firstname);
    $secondname =$db->santizeInput($secondname);
    $email =$db->santizeInput($email);
    $phonenumber = $db->santizeInput($phonenumber);
 
    if (checkLength($firstname) && checkLength($secondname))
    {	
	$sql = "insert into User (firstname, lastname, email, phoneNum) values (\"$firstname\",\"$secondname\",\"$email\", \"$phonenumber\")";
	$db->insertData($sql);
	echo "Data inserted";
    }
 
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<script language="javascript">
  /* check the length of the element, focus is none present */
  function lengthCheck(elem, thename)
  {
    if (elem.value.length> 0) 
      return true;
    else
    {
      alert("Please insert the " + thename);
      elem.focus();
    }
  }
 
  /* check a email address, using regular expression */
  function emailChecker(elem)
  {
    var reg = /^[\w\-\.\+]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
    if (elem.value.match(reg))
      return true;
    else
    {
      alert ("Please insert a valid email address");
      elem.focus();
      return false;
    }
  }
 
  /* check against a phone number. a number being between 11-15 numbers*/
  function checkPhone(elem)
  {
    var reg = /^[0-9]{11,15}$/;
    if (elem.value.match(reg))
      return true;
    else
    {
      alert ("Please insert a valid phone number");
      elem.focus();
      return false;
    }
  }
 
  function checkInputs()
  {
    // obtain inputs
    var firstname = document.getElementsByName("firstname").item(0);
    var secondname = document.getElementsByName("secondname").item(0);
    var email= document.getElementsByName("email").item(0);
    var phonenum = document.getElementsByName("phonenumber").item(0);
    /* check the inputs */
    if (lengthCheck(firstname, "first name")) 
      if (lengthCheck(secondname, "second name"))
	if (emailChecker(email))
	  if (checkPhone(phonenum))
	    return true;
    return false;
  }
</script>
</head>
<body>
<form name="input" action="insertData.php" method="post" onSubmit="return checkInputs()">
First Name :
<input type="text" name="firstname"/>
 
Second Name : 
<input type="text" name="secondname"/>
 
Email : 
<input type="text" name="email"/>
 
Phone number : 
<input type="text" name="phonenumber"/>
 
<input type="submit" value="Submit"/>
</form>
</body>
</html>

If you save that as insertData.php then open up within your web-server. You will be able to insert data into a database with some javascript / php checks.

Web page inputs and insert into database

Also from the other posts, Join files together and simple calculator , I was also asked to do

“Accept form input for a user registration form, and store results in a MySQL table, using PHP. Applicant should demonstrate a knowledge of input validation, and using server-side code to avoid sql injection exploits. The user data should include first name, last name, email, an phone number.

Usage of Javascript pre-validation would be a plus, as would forward planning, i.e. adding a unique code to the user details that could be used to validate their email address. Suitable MySQL table schema should be demonstrated.”

To start with, I started at the data insert within a web page

<body>
<form name="input" action="insertData.php" method="post" onSubmit="return checkInputs()">
First Name :
<input type="text" name="firstname"/>
Second Name : 
<input type="text" name="secondname"/>
Email : 
<input type="text" name="email"/>
Phone number : 
<input type="text" name="phonenumber"/>
<input type="submit" value="Submit"/>
</form>
</body>

Which takes in the required input’s and also within the form HTML tag, but before sending to the back end PHP part of the exercise, there was a requirement to do some Javascript checking on the inputs.

So here is the javascript that will check the inputs, within the form onsubmit action I call this function checkInputs and the return value (true/false) is returned which gives the form either a action to post back to the server (true return) or to wait for the user correct there inputs (false return).

    var firstname = document.getElementsByName("firstname").item(0);

I get the data from the webpage, getElementsByName (which since it is a name there could be x amount of elements with that name, so I want the first one (.item(0))

  function checkInputs()
  {
    // obtain inputs
    var firstname = document.getElementsByName("firstname").item(0);
    var secondname = document.getElementsByName("secondname").item(0);
    var email= document.getElementsByName("email").item(0);
    var phonenum = document.getElementsByName("phonenumber").item(0);
    /* check the inputs */
    if (lengthCheck(firstname, "first name")) 
      if (lengthCheck(secondname, "second name"))
	if (emailChecker(email))
	  if (checkPhone(phonenum))
	    return true;
    return false;
  }

and then after getting the elements, I then call different additional functions that I did write within javascript to check the inputs gained. Here I check the length of a element passed within the one of the parameters within the function parameter list, with using objects you can access the objects value.length (javascript object of a element) and also use the focus function with the element which will focus the element on the webpage for the user to know where to check there input (also with a alert window to say why, e.g. “please insert some data”.)

  function lengthCheck(elem, thename)
  {
    if (elem.value.length> 0) 
      return true;
    else
    {
      alert("Please insert the " + thename);
      elem.focus();
    }
  }

Here is a way of using regular expression to check email inputs, basically it first checks to make sure there is a name before the “@” and also a at between 2 and 4 names with a “.” better them.

  /* check a email address, using regular expression */
  function emailChecker(elem)
  {
    var reg = /^[\w\-\.\+]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
    if (elem.value.match(reg))
      return true;
    else
    {
      alert ("Please insert a valid email address");
      elem.focus();
      return false;
    }
  }

Here is a similar way as above for checking a phone number input between 11-15 numbers

  /* check against a phone number. a number being between 11-15 numbers*/
  function checkPhone(elem)
  {
    var reg = /^[0-9]{11,15}$/;
    if (elem.value.match(reg))
      return true;
    else
    {
      alert ("Please insert a valid phone number");
      elem.focus();
      return false;
    }
  }

This is the web page part, and here is the second part where I insert the data into database with php.

But here is the full web page part of the first part.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<script language="javascript">
  /* check the length of the element, focus is none present */
  function lengthCheck(elem, thename)
  {
    if (elem.value.length> 0) 
      return true;
    else
    {
      alert("Please insert the " + thename);
      elem.focus();
    }
  }
 
  /* check a email address, using regular expression */
  function emailChecker(elem)
  {
    var reg = /^[\w\-\.\+]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
    if (elem.value.match(reg))
      return true;
    else
    {
      alert ("Please insert a valid email address");
      elem.focus();
      return false;
    }
  }
 
  /* check against a phone number. a number being between 11-15 numbers*/
  function checkPhone(elem)
  {
    var reg = /^[0-9]{11,15}$/;
    if (elem.value.match(reg))
      return true;
    else
    {
      alert ("Please insert a valid phone number");
      elem.focus();
      return false;
    }
  }
 
  function checkInputs()
  {
    // obtain inputs
    var firstname = document.getElementsByName("firstname").item(0);
    var secondname = document.getElementsByName("secondname").item(0);
    var email= document.getElementsByName("email").item(0);
    var phonenum = document.getElementsByName("phonenumber").item(0);
    /* check the inputs */
    if (lengthCheck(firstname, "first name")) 
      if (lengthCheck(secondname, "second name"))
	if (emailChecker(email))
	  if (checkPhone(phonenum))
	    return true;
    return false;
  }
</script>
</head>
<body>
<form name="input" action="insertData.php" method="post" onSubmit="return checkInputs()">
First Name :
<input type="text" name="firstname"/>
 
Second Name : 
<input type="text" name="secondname"/>
 
Email : 
<input type="text" name="email"/>
 
Phone number : 
<input type="text" name="phonenumber"/>
 
<input type="submit" value="Submit"/>
</form>
</body>
</html>

Add-ons that make Firefox better developers environment

For me as a developer, there is some add-on’s within the Firefox better experience for me, I am using the following add-ons

Web developer

https://addons.mozilla.org/en-US/firefox/addon/60

This is a great developer addon, because you are able to view and update CSS, display allot of information about the web page itself, any missed links. It is the daddy of web developers tools for Firefox.

Search status

https://addons.mozilla.org/en-US/firefox/addon/321

For learning about SEO (Search engine optimization) and where you are in Page Rank/Alexa/MozRank/CompeteRank rankings, also it has keyword density, high no-follow links (for those websites that allow you to post but will not allow search engines to follow the link that you have posted to get better ranking, is this classed as not being nice !. not sure, I thought that is what the web was about !!) and other great tools.

Google Toolbar

http://www.google.com/intl/en_uk/toolbar/ff/index.html

It has gmail to allow you to check your emails without having a tab open, a little mail icon shows open if there is new mail, bookmarks so that you can carry them over to different computers (saves allot of time syncing bookmarks and fav’s links to different computers) and other great little tools within it.

If anyone else has any more great add-ons ?

MySQL – triggers

In MySQL version 5 onwards you can use Triggers, triggers are a nice was of checking values within a insert/update/delete process. A trigger happens either just before the insert actually happens into the database, or just after

Lets say that you create a table as below

CREATE TABLE testTable 
(id INT NOT NULL AUTO_INCREMENT, 
  guid VARCHAR(36), 
  name VARCHAR(100), 
PRIMARY KEY (id));

and then if you want to insert a name into the name column you could do

INSERT INTO testTable (name) VALUES ("thename");

but you are not inserting the anything into the guid column because you can force a value into that column with a trigger (the id is already creating a value with the primary key, auto_increment).

To create a trigger you need to set the delimiter to “//” because within sql you need to use the “;” which is the standard delimiter (when the MySQL will try and execute the query)

delimiter //
CREATE TRIGGER testTable_insert 
BEFORE INSERT ON 'testTable' 
FOR EACH ROW 
BEGIN 
    SET NEW.guid = uuid(); 
END;
delimiter ;

“CREATE TRIGGER” is just like creating a table, apart from you are creating a trigger, so the next value is the trigger name, normally it is the table name with what you are doing, e.g. inserting

“BEFORE INSERT ON” means before you actually insert the data into the database (it is in a hold area as such). the next value is the actual table that you are linking this trigger to.

“FOR EACH ROW” means each row of the insert, since you can insert x amount of lines into a table.

the sql code is between the “BEGIN” and “END”, and all is what is being set is the guid column within the “NEW” (this is the new row to be inserted) and setting that value to uuid() which is a mysql function.

so before you would have inserted into a table and the table would have looked like

ID GUID Name
1 thename

but once the trigger is in place and you did the same process again of inserting a new name

INSERT INTO testTable (name) VALUES ("a new name");
ID GUID Name
1 thename
1 3ace82c-2cf1-11df-b1c3-00a0d1a1240a a new name

Join files together into a single file and expand out

Again as with the previous post (simple calculator) this was another question to answer, which was fun to do.

“Write a class containing 2 functions. One function to merge 2 or more images into a single binary file. Write a counterpart function to this,which can extract the original files from the single binary, and write them out as single images, using their original filenames. Compression is not necessary, as the exercise is only designed to show an
understanding of using binary files with PHP, filesystem error handling, and planning a simple file format.”

Since we needed to have a simply file structure, so I decided to have a file structure of

Filename: <filename>
Size: <size in bytes>
<data>

where the filename, size in bytes and data (of the file itself) is filled in when the program runs.

So to start with I created a directory structure to pick up files from within one directory and place into another

/images
/newimages

and placed some images into the images directory.

To scan within a directory there is a iterator within PHP called DirectoryIterator which will do what it says on the tin, it will give you files within a directory and since being a iterator you can use a foreach to go through each file. Here is the syntax for DirectoryIterator to loop with a foreach (the $fileDirectory is the directory to scan and the $fileDetails is the files that are within the directory.

foreach (new DirectoryIterator($fileDirectory) as $fileDetails)

So what happens is that the program will loop through each file in the directory and open the single to write to, whilst looping through directory output the Filename to the single file and the Filesize, then read the actual file into a object to write to the single file within a binary format, and loop until no more files in that directory.

Then to un-single the file, I read the single file and find out the filename and filesize, open a file to write to in the new directory and read from the single file bits with the size of the filesize information from the single file, this was the actual file data, place this file data into the new file within the new directory. (kinder how tar works, builds all files into a single file from a directory and then expand then afterwards).

Here is the full code, it is small enough to hopefully follow.

<?php
  class imageBuilder 
  {
    /* read files into one file */
    /* file format 
      Filename: <filename>
      Size: <size in bytes>
      <data>
    */
    function readFiles($fileDirectory,$outputName)
    {
      $fHandle = fopen($outputName, "wb");
      if ($fHandle == false) throw new Exception("Error open file to write to");
      foreach (new DirectoryIterator($fileDirectory) as $fileDetails)
      {
	$filesize = filesize($fileDirectory."/".$fileDetails);
	if ($filesize > 0 && $fileDetails !="..")
	{
	  $rHandle = fopen($fileDirectory."/".$fileDetails, "rb");
	  if ($rHandle == false) throw new Exception("Error open file to read from");
	  $readInFile = fread($rHandle,$filesize);
	  if ($readInFile==false) throw new Exception("Error on reading file to read from");
	  fclose($rHandle);
	  if (fwrite($fHandle, "Filename: $fileDetails\n")==false) throw new Exception("Error writting data");
	  if (fwrite($fHandle, "Size : $filesize\n")==false) throw new Exception("Error writting data");
	  if (fwrite($fHandle,$readInFile)==false) throw new Exception("Error writting data");
	}
      }
      fclose($fHandle);
    }
 
    /* write files back out from the single file*/
    function writeFiles($fileDriectoryToWrite, $fileToReadFrom)
    {
      $rHandle = fopen($fileToReadFrom,"rb");
      if ($rHandle==false) throw new Exception("Error opening file to read");
      while (!feof($rHandle))
      {
	$filename = fgets($rHandle);
	$filename = trim(substr($filename, stripos($filename, ":")+1));
	if (strlen($filename) == 0) break;
	if ($filename == false) throw new Exception("Error reading the filename from file");
	$filesize = fgets($rHandle);
	if ($filesize ==false) throw new Exception("Error reading the filesize from the file");
	$filesize = trim(substr($filesize, stripos($filesize,":")+1));
	$readFileInfo = fread($rHandle, $filesize);
	if ($readFileInfo == false) throw new Exception("Error reading data from file to read from");
	$fHandle = fopen($fileDriectoryToWrite."/".$filename,"wb");
	if ($fHandle == false) throw new Exception("Error opening writing to file");
	if (fwrite($fHandle, $readFileInfo) == false) throw new Exception("Error writing to file");
	fclose($fHandle);
      }
      fclose($rHandle);
    }
  }
 
  $imageB = new imageBuilder();
  try {
    $imageB->readFiles("images","filetogether");
  }
  catch (Exception $ex)
  {
    echo "Error building the one file : $ex";
  }
 
  try {
    $imageB->writeFiles("newimages","filetogether");
  }
  catch (Exception $ex)
  {
    echo "Error writing files back out : $ex";
  }
 
?>

and you need to do is place some files within the /images directory and then run the program and it will create a single file called “filetogether” and also expand that file into the /newimages directory.

Simple calculator

Within a interview they requested me to do some exercises at home and here is the question that they posed.

“Create a simple stack-based calculator. This should be capable of performing addition, subtraction, multiplication and division. Example input would be: “2*(3+1)”. The result should be expressed as a numeric value, so the example should return 8. Usage of the eval() function, although amusing, is not allowed! This test is designed to show general programming skills, rather than an understanding of the programming platform; however the solution should be demonstrated using php as the language.”

So I decided to post on this site as well the design and program that I did come up with.

Since in maths you have to equate the ( .. ) first and then * , / , + , – so to start with I created a function that will pull out the brackets from the string input

    /* need to find the brackets and then equate the value and build outwards */
    public function equate()
    {
       // this is the string that was inputted when the class was created ( $this->calcstr;)
	$theStr = $this->calcstr;
 
	$bracketI = strrpos($theStr, "(");
	// there is a bracket
	while ($bracketI >=0)
	{
	  // find a bracket to match
	  $bracketEnd = strpos($theStr, ")", $bracketI);
	  if ($bracketEnd > 0)
	  {
	    // match then get the internal bracket value
	    $EqualMiddle = substr($theStr, $bracketI+1, ($bracketEnd-$bracketI)-1);
	    $calMiddle = $this->calculateTheString($EqualMiddle);
	    // rebuild the string without the bracket but with the value
	    $theStr = substr($theStr,0, $bracketI) . $calMiddle. substr($theStr, $bracketEnd+1);
	  }
	  else
	    throw new Exception("Bracket miss matched");
 
	  $bracketI = strrpos($theStr, "(");
	  if ($bracketI == false && $theStr[0] != "(") break;
	}
	return $this->calculateTheString($theStr);
    }

So what happens is that it will find the last occurrence of a bracket “(” and then find the corresponding “)” for that bracket, error is not found. Once found, it will then send to a function called “calculateTheString” that will actually calculate the value.

The calculateTheString function

 private function calculateTheString($theStr)
    {
	// look for * / + - in that order and then get the number each side to do the math
	$mathStr = array("*", "/", "+", "-");
	foreach ($mathStr as $maths)
	{
	  do 
	  {
	    // find each occurence of the math func
	    $mathI = strpos($theStr, $maths);
	    if ($mathI > 0)
	    {
	      // find the numeric values before and after the math func
	      try {
		$valueBefore = $this->getNumbericValue(substr($theStr, 0,$mathI), 0);
		$valueAfter =  $this->getNumbericValue(substr($theStr, $mathI+1), 1);
	      } catch (Exception $ex)
	      {
		echo "Error : $ex (String = $theStr)";
	      }
	      // do the math func
	      switch($maths)
	      {
		case "*" : $newV = $valueBefore * $valueAfter; break;
		case "/" : $newV = $valueBefore / $valueAfter; break;
		case "+" : $newV =$valueBefore + $valueAfter; break;
		case "-" : $newV =$valueBefore - $valueAfter;; break;
		default : $newV =0;
	      }
	      // rebuild string without the math func that is done
	      $theStr = substr($theStr,0,($mathI-strlen($valueBefore))) . ($newV) . substr($theStr,($mathI+strlen($valueAfter)+1));
	    }
	  } while ($mathI >0);
	}
	return $theStr;
    }

will loop through the math functions (*,/,+,-) in order of calculation, if it finds one of them it will equate what the value of that block of math is e.g.

4*2+1

it would equate the 4*2 and then rebuild the string to have the result within the next loop e.g.

8+1

so that when it gets to the + math function it will add 8 to 1.

To get the number values before and after the math functions (*,/,+,-) I created a function to pull out the values called “getNumbericValue”.. since the values will either be before or after the e.g. going backwards or forwards in the string, then you will need to either go in that direction. Once you have got the area within the string of the numeric values, then use the intval to convert into a integer value. The is_numeric makes sure that there is still a numeric value present.

/* $theStr = string to search, leftOrRight means going left or right in the string, 0 = left, 1=right*/
    private function getNumbericValue($theStr, $leftOrRight=1)
    {
	if (strlen($theStr) == 0) throw new Exception("No number value");
	if ($leftOrRight ==1) { $pos =0; 
	  $start = 0;
	}else 
	{
	  $pos = strlen($theStr)-1;
	  $start = strlen($theStr) -1;
	}
 	while (true)
	{
	  if (is_numeric($theStr[$pos]))
	  {
	    if ($leftOrRight == 0) $pos--; else $pos++;
	  }
	    else break;
	}
	// if just the number at the start
	if ($pos == -1) return intval($theStr);
	// if the start is greater than the end point, change over
	if ($start > $pos) { $tmp = $pos; $pos = $start; $start = $tmp;}
	return intval(substr($theStr,$start, $pos));
    }

To build all that together with

<?php
  class calc 
  {
    private $calcstr = "";
 
    function __construct($strIn)
    {
      $this->calcstr = $strIn;
    }
 
    public function setStr($strIn = "")
    {
      $this->calcstr = $strIn;
    }
 
    /* $theStr = string to search, leftOrRight means going left or right in the string, 0 = left, 1=right*/
    private function getNumbericValue($theStr, $leftOrRight=1)
    {
	if (strlen($theStr) == 0) throw new Exception("No number value");
	if ($leftOrRight ==1) { $pos =0; 
	  $start = 0;
	}else 
	{
	  $pos = strlen($theStr)-1;
	  $start = strlen($theStr) -1;
	}
 	while (true)
	{
	  if (is_numeric($theStr[$pos]))
	  {
	    if ($leftOrRight == 0) $pos--; else $pos++;
	  }
	    else break;
	}
	// if just the number at the start
	if ($pos == -1) return intval($theStr);
	// if the start is greater than the end point, change over
	if ($start > $pos) { $tmp = $pos; $pos = $start; $start = $tmp;}
	return intval(substr($theStr,$start, $pos));
    }
 
    private function calculateTheString($theStr)
    {
	// look for * / + - in that order and then get the number each side to do the math
	$mathStr = array("*", "/", "+", "-");
	foreach ($mathStr as $maths)
	{
	  do 
	  {
	    // find each occurence of the math func
	    $mathI = strpos($theStr, $maths);
	    if ($mathI > 0)
	    {
	      // find the numeric values before and after the math func
	      try {
		$valueBefore = $this->getNumbericValue(substr($theStr, 0,$mathI), 0);
		$valueAfter =  $this->getNumbericValue(substr($theStr, $mathI+1), 1);
	      } catch (Exception $ex)
	      {
		echo "Error : $ex (String = $theStr)";
	      }
	      // do the math func
	      switch($maths)
	      {
		case "*" : $newV = $valueBefore * $valueAfter; break;
		case "/" : $newV = $valueBefore / $valueAfter; break;
		case "+" : $newV =$valueBefore + $valueAfter; break;
		case "-" : $newV =$valueBefore - $valueAfter;; break;
		default : $newV =0;
	      }
	      // rebuild string without the math func that is done
	      $theStr = substr($theStr,0,($mathI-strlen($valueBefore))) . ($newV) . substr($theStr,($mathI+strlen($valueAfter)+1));
	    }
	  } while ($mathI >0);
	}
	return $theStr;
    }
 
    /* need to find the brackets and then equate the value and build outwards */
    public function equate()
    {
	$theStr = $this->calcstr;
 
	$bracketI = strrpos($theStr, "(");
	// there is a bracket
	while ($bracketI >=0)
	{
	  // find a bracket to match
	  $bracketEnd = strpos($theStr, ")", $bracketI);
	  if ($bracketEnd > 0)
	  {
	    // match then get the internal bracket value
	    $EqualMiddle = substr($theStr, $bracketI+1, ($bracketEnd-$bracketI)-1);
	    $calMiddle = $this->calculateTheString($EqualMiddle);
	    // rebuild the string without the bracket but with the value
	    $theStr = substr($theStr,0, $bracketI) . $calMiddle. substr($theStr, $bracketEnd+1);
	  }
	  else
	    throw new Exception("Bracket miss matched");
 
	  $bracketI = strrpos($theStr, "(");
	  if ($bracketI == false && $theStr[0] != "(") break;
	}
	return $this->calculateTheString($theStr);
    }
 
  }
 
  $theequal = "2*(3+1)";
  $thecalc = new calc($theequal);
  try {
    echo $thecalc->equate();
  } catch (Exception $err)
  {	
    echo $err;
  }
?>

and the output would be

8

I found it a interesting exercise 🙂

AJAX – setup and test

AJAX is the way of communicating with a back end server without having to send the full information (you can of course) but for example you could just send a username check to see if it is available, but the main thing is that you do not send back a full page but only the part that you want to update.

With reference to the example of a username, you could just send the username and send back either yes or no response which saves allot of time and traffic from the client to the server (and makes the whole web page experience nicer).

All the AJAX is shorthand for “Asynchronous JAvascript and Xml”, asynchronous means that you can do something else whilst waiting for the response (put the kettle on and get a cup for the drink whilst the kettle is boiling) thus with javascript on the client web browser sends a request to a web page on the server with XML wrappings.

To get the basics lets start with the being

  // this function will return a XmlHttpRequest object that allows you to "talk" to the server.
  function GetXmlHttpObject()
  {
      // IE7+, FF, Chrome, Opera, Safari
      if (window.XMLHttpRequest) return new XMLHttpRequest;
 
      // IE6 , IE5
      if (window.ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP");
  }

the GetXmlHttpObject will return a object that will allow the javascript to talk to the backend server, the newer version is call a XMLHttpRequest whilst on older browsers it was part of the ActiveXObjects.

The next is to send a request to the backend server

    xmlHttpObject.onreadystatechange=callBackFunction;
    xmlHttpObject.open("GET", GetUrl, true);
    xmlHttpObject.send(null);

The onreadystatechange, will call a function (in javascript on the client browser) when the request alters from different states, the different states are

  • 1.open method invoked successful, open a connection with the server
  • 2.server responsed with a valid header response.
  • 3.server has sent some data, the response content is started to load.
  • 4.server has finished sending all of data

so from reading the states, you are really interested in state 4, because that will have the data (server response) that you are interested in for this.

The .open forms the request to the XmlHttpRequest object to call (“GET” in HTML) the server web site, the GetUrl is just a variable that well call a php page (“ajaxbackendcall.php”) which takes a parameter called name and returns a string with the name in reverse (shall include that source code later).

And then the .send will start the ready states to change and sends the request to the backend server, here is the function that is called on the state change

  function callBackFunction()
  {
    if (xmlHttpObject.readyState == 4)
      alert(xmlHttpObject.responseText);
  }

What is happening here, is that from the state stages I am waiting on ready state to equal 4 ( when the server has finished responding) and then output the response from the responseText which is filled from the AJAX call to the backend server.

That is mainly it, here is some full code for you to try out save this as “codingfriends.com.ajax.test.html”

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html3/strict.dtd">
<html>
<head>
<script type="text/javascript">
  // the xmlHttpRequest object
  var xmlHttpObject;
 
  // the ajax call 
  function getInnerText()
  {
    // get the name to send to the server backend page
    var namehere = document.getElementById("namehere");
 
    // request the xmlHttpObject 
    xmlHttpObject = GetXmlHttpObject();
 
    // if there is not xmlHttpRequest object being allowed to be created then the browser does not support it.
    if (xmlHttpObject==null)
    {
      alert("Browser does not support XmlHttp calls e.g. AJAX");
      return;
    }
 
    // fill in the request details, e.g. the url to call and also the query string inserted into the url
    var GetUrl = "ajaxbackendcall.php"+"?name="+namehere.value;
 
    // here is the call to the server.
    // to start with setup which function to call when a ready state on the XmlHttpRequest object has changed
    xmlHttpObject.onreadystatechange=callBackFunction;
    // request the html "GET" to obtain the url (e.g. the backend server page, dynmaic normally)
    xmlHttpObject.open("GET", GetUrl, true);
    // and then issue it
    xmlHttpObject.send(null);
  }
 
  // the function that is called once the XmlHttpRequest object state has changed
  /* the readyStates are 
    1 open method invoked successful, open a connection with the server
    2 server responsed with a valid header response.
    3 server has sent some data, the response content is started to load.
    4 server has finished sending all of data
  */
  // so we listen for readyState 4 when all finished
  // and output the response text into the div id innertextoutput
  function callBackFunction()
  {
    if (xmlHttpObject.readyState == 4)
      document.getElementById("innertextoutput").innerHTML=xmlHttpObject.responseText;
  }
 
  // this function will return a XmlHttpRequest object that allows you to "talk" to the server.
  function GetXmlHttpObject()
  {
      // IE7+, FF, Chrome, Opera, Safari
      if (window.XMLHttpRequest) return new XMLHttpRequest;
 
      // IE6 , IE5
      if (window.ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP");
  }
</script>
</head>
<body>
<a href="#" onclick="javascript:getInnerText()">click here to return text from a ajax call</a>
<br/>
Enter the name here <input id="namehere"/>
<br/>
<div id="innertextoutput"></div>
</body>
</html>

and then save this as the ajaxbackendcall.php file to call (in the same directory as the code above and also within a directory that has PHP plugin enable for that webserver be it apache or IIS.

<?php
    $name = $_GET['name'];
 
    // change the output to say something else, here I am just reversing the name
    if (strlen($name) > 0)
    {
      // have to insert something into it so that php does not make it into a array but a string
      $namereturn="0";
      $j = 0;
      for ($i = strlen($name)-1; $i >= 0; $i--)
      {
        $namereturn[$j++]=$name[$i];
      }
      echo "normal name {$name} and in reverse {$namereturn}";
    }
    else
      return "No name inputted";
?>

The output would be similar to the below. OUTPUT

click here to return text from a ajax call
Enter the name here

END OF OUTPUT

If you do not have a PHP webserver to test with, you can just alter the codingfriends.com.ajax.test.html code by altering the backend web page to call to this

var GetUrl = "nonephpbackend.html"

and create a page within the same directory as the codingfriends.com.ajax.test.html page and place something inside it like

hi there