Monday, May 06, 2013

HTML Select element manipulation using Javascript - I

SelectBox, the HTML <select> element, is an useful thing which we use on various webpages. Here we would be discussing on the following points with select element.

1. List All options and their values
2. Show selected option's text and value
3. Append new options at the end of the list
4. Add new options at the top of the list
5. Add new options at any position of the list
6. Remove a single options from the list
7. Remove all/multiple options from the list
8. Edit any option at any position within the list
9. Create a copy of the select element and append it to the body.
10. Sorting all options in a Select element

11.  Select/UnSelect all options in a Select element

Here we would be solving each point. Here is the select element :

<select id='selectBox' name='selectBox'>
<option value=''   > Select a Bike Model </option>
<option value='suz'> Suzuki </option>
<option value='duc'> Ducati </option>
<option value='hnd'> Honda </option>
<option value='yam'> Yamaha </option>
<option value='kwk'> Kawasaki </option>
<option value='apr'> Aprilia </option>
</select>



1. List All options and their values :

<script>
// Get the Select element
var p = document.getElementById("selectBox");
var str = "";

// Loop each item
for(i=0; i<p.options.length; i++)
{
  var option = p.options[i].textContent ? p.options[i].textContent : p.options[i].innerText;
  str +=  p.options[i].value + " : " + option + "\n";
}

alert( str );
</script>


The output would be :

 : Select a Bike Model
suz : Suzuki
duc : Ducati
hnd : Honda
yam : Yamaha
kwk : Kawasaki
apr : Aprilia

The first does not have a value specified, hence it is showing nothing in the first row of output. To get the option text, we use textContent for non-IE browser and innerText for IE. Option index starts from 0.

2. Show selected option's text and value

First, we create a function which takes option number as its argument and shows that option on screen. Option list is an array of all the texts starting with index zero.

<script>
var option = getOption ( 2 );

function getOption( option_no )
{
    // Get the Select element
    var p = document.getElementById("selectBox");

    // Declare empty object
    var str = new Object;

    // Try to get that option
    if( p.options[ option_no ] == undefined )
    {
       /// That index is invalid
       /// Hence Empty Object would be returned
    }
    else
    {
      /// Valid Index has been used
      str.option = p.options[option_no].textContent ? p.options[option_no].textContent : p.options[option_no].innerText ;
      str.value  = p.options[option_no].value;

    }

    return str;
}
</script>


The code above is quite self-explanatory. We have also checked whether the passed index is invalid or not. For example, if we call :

var option = getOption( 32 );  /// Out of bound Index

an empty object would be returned to "option" variable. The expression :

p.options[ option_no ] == undefined

checks whether that indexed location exists or not within the options array.


When any option is selected, the 'selectedIndex' property of the select element automatically holds the index number of that item. Hence to get the value and text of the selected item, we need to write the following statements ...

var s = p.options.selectedIndex;
var opt2 = get_option( s );
alert(opt2);

We are simply passing the index of selected option item to the get_option function and the return string ( consisting option text and value ) is collected in variable opt2.

3. Append new options at the end of the list

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Create a Dynamic Option called Hyosung
var o = new Option("Hyosung", "hyo");

// Append the new option to the select element
p.appendChild( o );
</script>


We are just creating new option object with the keyword 'new', and the "Option" constructor call takes 2 arguments - Option Text and Option Value. Then we are appending the new option object to SelectBox element. This new option is automatically appended at the end of the list.

The above code may not work in old versions of IE (in IE9 it is okay). In that case we can write the below code which would run in all browsers without any problem.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Create a Dynamic Option called Hyosung
p.options[ p.options.length ] = new Option("Hyosung", "hyo");
</script>

Another function add() would add new options to the list at the last position.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// use add() method
p.options.add( new Option('Hyosung', 'hyo') );
<script>


Or we can add new options the following way ... this would run on all browsers including IE 7 and 8.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Create new Option element
var opt = document.createElement("option");

// Set properties
opt.text = "Hero";
opt.value = "hro";

// Use add() method to add new options
p.options.add( opt );
</script>



4. Add a new options at the top of the list

We can do it in 2 ways, 1 is long and second is very short. Both the methods are discussed below.

1. In this method, we are going to follow these steps..
   a. Copy all the options of the selectbox to an array
   b. Create a new option object
   c. Insert the new option at the beginning of the array
   d. Remove all options from the selectbox
   e. Insert all options from the array to selectbox element using appendChild() method

Check the code below.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Copy all the options to an array
var str = [];
var i;

// We are ignoring the "Select a Bike Model" option at index 0
for( i=1; i<p.options.length; i++)
{
  str[i] = p.options[i];
}

// Create a Dynamic Option called Hero
var o = new Option("Hero");

// Add value to it
o.setAttribute("value", "hro");

// Insert the new option at the beginning of array
str[0] = o;

// Remove all options from the selectbox
p.options.length = 1;  // "Select a Bike Model" option remain untouched

// Insert all options fom array to Select Box
for( i=0; i<str.length; i++)
{
  p.appendChild( str[i] );
}

</script>


2. This was a long road to achieve what we wanted. Now is the tun for the short-cut route. Check the second method ..
   a. Create a new option object
   b. Find a position where we would be inserting the new option
   c. Insert the new option into the selectbox using insertBefore() method. insertBefore() takes 2 parameters, new node and reference node and as a result, the new node is inserted before the reference node. If reference node is null, the the new node is inserted at the end of the list of options.

Check out the javascipt implementation below.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Create a Dynamic Option called Hero
var o = new Option("Hero");

// Add value to it
o.setAttribute("value", "hro");

// Get the first option, zeroth option is "Select a Bike Model"
var n = p.options[1];

// Insert the new option directly
p.insertBefore( o, n);
</script>


The above methods would not give proper results in older versions of IE. On IE9, they would work perfectly. We can have the following code for getting the proper results in IE7/IE8.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Copy all the options to an array
var str = [];
var i;

// We are ignoring the "Select a Bike Model" option at index 0
for( i=1; i<p.options.length; i++)
{
  str[i] = p.options[i];
}

// Create new Option
str[0] = new Option("Hyosung",'hyo');

// Increase the Option List Count
// Create a placeholder in the select element

p.options.length ++;

// Now copy all option nodes from array to Select element
for( i=1; i<p.options.length; i++)
{
  p.options[i] = str[i-1];
}
</script>


The above code ran well in IE7/IE8. It is quite self-explanatory. We area creating an array and pushing all the options to that array. After that, we create a new Option object and push it to the array. Then we create a new placeholder in the option list of the select element to fit in the new option. Finally we copy all the items of array to the select element's options list. We can use the same method to insert any new Option in the middle position of an option list. Insertion in the middle of such option list is discussed in point 5 below.

Notes :
We can use innerHTML property of select element to insert new options but this would remove all old options.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Overwite everything inside
p.innerHTML = "<option value='1'>1</option> <option value='2'>2</option> <option value='3'>3</option>";
</script>


The above code would insert 3 new options into the select element and erase all old options. However this does not work in IE older versions. The innetHTML method really comes handy when we fetch dynamic options from an ajax call. After we receive the bunch of options as ajax response, we can simple assign it to the innerHTML property of a select element. This is shown below..

<script>
document.getElementById('selectBox').innerHTML = ajaxResponseText;
</script>


5. Add new options at any position of the list

Using insertBefore() method we can insert a new option at any position into a select element. If the second parameter to insertBefore() is null, then the new option is added at the end of the list of options. Check out the code below.

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Create a Dynamic Option called Hero
var o = new Option("Hero");

// Add value to it
o.setAttribute("value", "hro");

// Insert "Hero" before "Kawasaki"
// Locate the "Kawasaki" node first

var refer_node = p.options.item(5);

// Now Insert "Hero"
p.insertBefore( o, refer_node );

// Now insert it before "Aprilia"
refer_node = p.options.item( 2 );
p.insertBefore( o, refer_node );

// See THAT the new node o has been moved
// From its previous place (place before Kawasaki)
// to new place (place before Aprilia)


// Remove all Old options
p.options.length = 0;

// Inserts at the end
p.insertBefore(o, null);

/// Multiple Inserts with same node is not possible.
/// A node already inserted, cant be inserted again

p.insertBefore(o, null); // Ineffective
p.insertBefore(o, null); // Ineffective

/// Use cloneNode() to clone a node and insert
var o2 = o.cloneNode();
p.insertBefore(o2, null); // Works
</script>


The above code works in IE9 and other browsers like Firefox and chrome. For IE7/IE8, we can use the method discussed in point 4 above.

Notes ::
1. To Update any old option with new one, we can write the following code :

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// OverWrite the old Option with new item
p.options[3] = new Option('Option Text', 'Option Value');
</script>


2. To Insert empty elements to the option list, write following code

<script>
// Get the Select element
var p = document.getElementById("selectBox");

// Insert empty elements at the end
p.options.length = 100;
</script>


The above code increases the option array length to 100 which means if it already has 7 elements in it, 93 more empty options are added to it.

3. We can populate a select element taking values from an javascript object as shown in below example.. This runs on all browsers.

<script>
// Define Object
var obj = { duc:'Ducati', suz:'Suzuki', apr:'Aprilia' };

// Get the Select element
var p = document.getElementById("selectBox");

// Iterate Object properties
for(var i in obj)
{
    // Create new Option element
    var opt = document.createElement("option");

    // Set properties
    opt.text  = obj[i];
    opt.value = i;

    // Add it to Options array
    p.options.add( opt );
}
</script>


Check the next part here.

Tuesday, April 30, 2013

Select multiple checkboxes using Javascript and jQuery

Suppose, we have a form as shown below.



It has 3 buttons, when the "Select All" button is clicked, all the checkboxes are checked, while "Select None" button unchecks all the chekboxes. Now, we need to write two javascirpt functions which checks/unchecks all the checkboxes at once. Check out the code below.

<html>
<head>
<script type='text/javascript'>

function fselect_all()
{
 // IE 8 and others support querySelectorAll()
 var col = document.querySelectorAll("input[type=checkbox]");
 for(var i=0; i<col.length; i++ )
 {
   col[i].checked = true; // Check
 }
}

function fselect_none()
{
  // IE 8 and others support querySelectorAll()
 var col = document.querySelectorAll("input[type=checkbox]");
 for(var i=0; i<col.length; i++ )
 {
   col[i].checked = false; // Uncheck
 }
}
</script>
</head>
<body>

<form>
<table>
 <!-- Dynamic Generation of Table Items -->
<?php
  for( $i=1;$i<=10; $i++)
  {
?>
   <tr>
    <td>
      <input type='checkbox' name="sel[<?php echo $i;?>]">
      Item <?php echo $i;?> </td>
   </tr>
<?php 
  }
?> 
 <tr>
  <td>
    <input type='button' value='Select All' onclick='fselect_all()'>
    <input type='button' value='Select None' onclick='fselect_none()'>
    <input type='submit' value='Submit' name='btn_submit'>
  </td>
 </tr>
</table>
</form>
</body>
</html>


Some points to be noticed in the above piece of code ::
1. We are generating the checkboxes using a PHP for loop which generates the following table rows ..

 <tr><td><input type='checkbox' name="sel[1]">  Item 1 </td></tr>
 <tr><td><input type='checkbox' name="sel[2]">  Item 2 </td></tr>

  ...
2. In the fselect_all()  and fselect_none() functions, we are using querySelectoAll() method which is supported in all new browsers. IE8 onwards have support for it. This function takes CSS like selectors for selecting DOM nodes and returns all the matching node/elements as a collection it finds. Then we simply run a Javascript for() loop to iterate each checkbox item and then we set their "checked" property to true or false as needed.

The above task can be easily done using jQuery. Check the new fselect_all() and fselect_none() functions which use jQuery statements for checking/unchecking checkboxes.

function fselect_all()
{
  $("input[type=checkbox]").each(function(){ this.checked = true; });
}

function fselect_none()
{
  $("input[type=checkbox]").each(function(){ $(this).removeAttr('checked'); });
}


The statement " this.checked = true; " is a Javascript one, using the statement $(this).attr('checked',true); instead checks the checkboxes only once. This phenomenon can be seen on jsFiddle. Hence we better use the old Javascript statement for checking all checkboxes.

To add checked='checked' to a Checkbox, we can use jQuery's prop() method. And to remove the check, instead of using removeAttr('checked') we can use removeProp(' checked') method. Adding  checked='checked' using the prop() method may not appear in FireBug etc tools.

Now, we would submit the form and see how the inputs are captured at the server end. Check the PHP code below.

<?php
if( isset($_REQUEST['sel']) )
{
   /// Iterate the Items
   foreach( $_REQUEST['sel'] as $key => $val)
   {
     /// Get the ID
     $customer_id = $key;
    
     /// Do some SQL queries
     ...
   }

}

?>

Only selected items will be captured in the above array at the server side. In the PHP loop above, $val for all the array items would have a value of "on". When a checkbox is checked and submitted, server gets a value of "on" against the element's name unless a value is specified as shown below :

<input type='checkbox' name='sel[]' value='test 1'>

Friday, April 26, 2013

Submitting Forms with multiple textboxes having same name

Creation of table with dynamic textboxes has been shown here. In such scenarios, it is good to name the textbox elements as "row[]" or "text[]" which look like an array construction. When the form is submitted, all the textbox's values will be available to PHP in an array which would be very easy for further processing.

Suppose, all the textboxes have a name structure like "text[]" as shown in the example form below.

<!-- FORM STARTS -->
<form name='f' method='post'>

<!-- INPUT Elements -->
<input type='text' name='text[]' value='0'>
<input type='text' name='text[]' value='1'>
<input type='text' name='text[]' value='2'>
<input type='text' name='text[]' value='3'>

<input type='submit' name='btn_submit' value='Submit Me'>

</form>
<!-- FORM ENDS -->


When we submit the form above, PHP receives values of all the textbox elements in an array format in variable $_POST['text']. If we run the following PHP statement :

<?php
print_r( $_POST['text'] );
?>


the output would be :

Array
(
    [text] => Array
        (
            [0] => 0
            [1] => 1
            [2] => 2
            [3] => 3
        )
)


If we give different index with the element as shown below :

<input type='text' name='text[123]' value='0'>
<input type='text' name='text[125]' value='1'>
<input type='text' name='text[147]' value='2'>
<input type='text' name='text[189]' value='3'>


the PHP  statement print_r( $_POST['text'] ); would give the following output.

Array
(
    [text] => Array
        (
            [123] => 0
            [125] => 1
            [147] => 2
            [189] => 3
        )
)


Creation of such textboxes can be done with the following piece of PHP code.

<table>
<?php
 for($i=0; $i<10; $i++)
 {
?>
  <tr>
    <td>
      <input type='text' name='text_<?php echo $i;?>'>
    </td>
  </tr>
<?php
}
?>
</table>


This generates the following HTML code. Notice the element's name is a bit different.

<table>
  <tr>
    <td> <input type='text' name='text_0'> </td>
  </tr>
  <tr>
    <td> <input type='text' name='text_1'> </td>
  </tr>
  <tr>
    <td> <input type='text' name='text_2'> </td>
  </tr>
  <tr>
    <td> <input type='text' name='text_3'> </td>
  </tr>
</table>


The statement :

<input type='text' name='text[<?php echo $i;?>]'>

would generate input elements like this :

<input type='text' name='text[0]'>
<input type='text' name='text[1]'>


But we can still manage to collect the element's value, after the form is submitted, easily.

<?php
for($i=0; $i<10; $i++)
{
  $index = "text_" . $i;
  echo $_POST[$index] . ", ";
}
?>


Now, a question ... what if all the elements share a common name as shown in the HTML below?

<input type='text' name='text' value='0'>
<input type='text' name='text' value='1'>
<input type='text' name='text' value='2'>
<input type='text' name='text' value='3'>


Only the last element's value will be available to PHP i.e $_POST['text'] would collect only last element's value of "3".

Thursday, April 25, 2013

Creating Dynamic Table Rows and Columns In Javascript

Before we get into the solution, here I first discuss the problem we are going to solve through Javascirpt.

Problem : We have a HTML page which looks like this:

  



 



The coresponding HTML is also given below.

<html>
<body>
<table id="table"></table>
<input type='button' value='Add New' id='button' onclick='add_new()'>
</body>
</html>


Now when we click on "Add New" button, a new row is created and appended to the <table> element shown in the above HTML. If we repeat it couple of times, we would be generating a big dynamically generated table as shown in the picture below ...


The "Click Me" button, when clicked,  shows a message with the coresponding row number as shown in the picture below.




The "Remove Me" buttons delete the corresponding row. And if we remove couple of rows the page becomes like this ..




The above scenario would involve dynamic creation of table rows (tr) and cells (td) in Javascript. Let me put the solution below and then we would dissect each part of the code. Check the Full HTML and Javascript code below.

<html>
<head>
<script type='text/javascript'>
   
//// When ClickkMe button is clicked   
function checkMe(id)
{
   alert("I am Row : " + id);
}
   
// Remove any Row from the Table
function removeMe(id)
{

  // Get the Table
  var t = document.getElementById('table');
 
  // Delete the Selected Row
  t.deleteRow(id);
 
  // Re-Index the Rows Heading
  for(var j=0;j<t.rows.length; j++)
  {
     /// Index Row Numbers
     var tr = t.rows[j];
    

     // FOR IE
     if(tr.children[0].innerText)
        tr.children[0].innerText = "Row : " + j;
     // FOR Others 
     else if(tr.children[0].textContent)
        tr.children[0].textContent = "Row : " + j; 
  }
 
  /// GET all CLICK ME buttons
  var p = document.getElementsByName('button_click');
 
  /// We need to re-define the onclick behaviour of these buttons
  /// checkMe() takes corresponding row number to show the message
  for(var j=0; j<p.length; j++)
  {
    p[j].setAttribute("onclick", "checkMe("+j+")");
  }
 
  /// GET all REMOVE ME buttons
  var p = document.getElementsByName('button_remove');
 
  /// We need to re-define the onclick behaviour of these buttons
  /// removeMe() takes corresponding row number to delete
  for(var j=0; j<p.length; j++)
  {
    p[j].setAttribute("onclick", "removeMe("+j+")");
  }

}

// Addition of a new row at the end of the Table
function add_new()
{
  // GET The Table
  var t = document.getElementById('table');
 
  // GET row count
  var lastrow = t.rows.length;
 
  // Insert Row at the End
  var row = t.insertRow(lastrow);

  // leftmost Cell showing Row No :
  var cellLeft = row.insertCell(0);
  var textNode = document.createTextNode("Row : " + lastrow);
  cellLeft.appendChild(textNode);

  // Next Cell/TD for Input Element
  cellLeft = row.insertCell(1);
  var i = document.createElement('input');
  i.setAttribute('type','text');
  i.setAttribute('value',lastrow);
  i.setAttribute('name','text'+lastrow);
  cellLeft.appendChild(i);

  // Next Cell/TD for 'Click ME' button
  cellLeft = row.insertCell(2);
  i = document.createElement('input');
  i.setAttribute('type','button');
  i.setAttribute('name','button_click');
  i.setAttribute('value','Click Me');
  i.setAttribute('onclick','checkMe('+lastrow+')');
  cellLeft.appendChild(i);

  // Next cell/TD for 'Remove Me' button
  cellLeft = row.insertCell(3);
  i = document.createElement('input');
  i.setAttribute('type','button');
  i.setAttribute('name','button_remove');
  i.setAttribute('value','Remove Me');
 
  /// We define the onclick behaviour of each remove button
  i.setAttribute('onclick','removeMe('+lastrow+')');
  cellLeft.appendChild(i);

}
</script>
</head>
<body>
<table id="table"></table>
<input type='button' value='Add New' id='button' onclick='add_new()'>
</body>
</html>


Explanation ::

a. The add_new() function does a lot of job when we click the "Add New" button.
    

    1. First we reach to the table through getElementById('table') method, then we use insertRow() method to insert a new row at the position specified by lastrow. The lastrow variable holds last row's position as t.rows.length returns the total number of rows in the table. The last row created is returned in variable row.
   

   2. Now, add a new cell to the row where the text "Row : 0" would appear. The first row starts from index zero in our example. Then we create cells in that row starting form index 0. The method insertCell(0) created first cell, insertCell(1) creates second cell (td element) etc. in that row.
   

   3. For the fist cell, we create only a text node with document.createTextNode() method. After we create a node, we must append it to the cell associated with it. The statment cellLeft.appendChild(textNode); does it.
   

   4. The next cell at position 1, which was created with row.insertCell(1) is going to have an Input field which would also show Row Number. For creating any element within the HTML, we need to use document.createElement() method with element type as argument. Hence document.createElement('input') creates an input element but does not append it to the cell associated with it. Until and unless we do so ( append the input element to a <td> cell  by calling appendChild() ), it does not get rendered by the browser. Next, we add some attributes to the input element by setAttibute() method.
   

    The statement setAttribute('name','text'+lastrow); would add "name" property to that input element and assign "text0" or "text1" etc. value to that property. We would not see any effect of adding & setting the 'name' property of that text input element here, but this might be useful if we want to submit the form including the table above with some required input.
   

   5. Then we again call the appendChild() method to append the new input element to the parent cell or <td> element.
   

   6. Similarly, we create two more input element (type button) and append them to their associated cells.
   

       The following statement :
      i.setAttribute('onclick','checkMe('+lastrow+')');
      gives the input element a property like "onclick = 'checkMe(1)'".
     
       The statement :
      i.setAttribute('onclick','removeMe('+lastrow+')');
      gives the last input element a property like "onclick = 'removeMe(1)'".

      The removeMe() function actually removes the row which is passed to it as a parameter.

b. The removeMe() function is called when "Remove Me" button corresponding to any row is clicked. This function deletes the row. 

   
  For example :
   removeMe(2);
   would delete the row number 2 (the third row from top). Row number 0 would refer to the first row from the top.
  
   We use
   t.deleteRow(id); // id is the row index,
   to delete any particular row. 


It works like an array. If a table has 4 rows [ index 0,1,2,3 ] and we delete any row from this array it becomes [ index 0,1,2 ]. Again if we delete a row, it becomes [ index 0,1 ]. Deleting rows would involve some critical situation. Suppose, there are 4 rows with index 0,1,2,3 with remove button's onclick events are shown below :
   

   1st row's [index 0] "Remove Me" button's onclick event -- removeMe(0)
   2nd row's [index 1] "Remove Me" button's onclick event -- removeMe(1)
   3rd row's [index 2] "Remove Me" button's onclick event -- removeMe(2)
   4th row's [index 3] "Remove Me" button's onclick event -- removeMe(3)

   Now when we delete 2nd row [index 1] by calling removeMe(1), the row indexes become 0,1,2 as it works more like an array. But the all the "Remove Me" button's onclick events remain as shown below ...
   

   1st row's [index 0] "Remove Me" button's onclick event -- removeMe(0)
   3rd row's [index 1] "Remove Me" button's onclick event -- removeMe(2)
   4th row's [index 2] "Remove Me" button's onclick event -- removeMe(3)

   The row indexes are updated within the table while the function calls are not updated. At this situation, if we try to call the last row's removeMe(3) function, this would generate an error as index 3 is not available. Table row indexes are 0,1,2 now. The following code gets all the remove buttons in variable p, and then we change the onclick property.

   var p = document.getElementsByName('button_remove');
 for(var j=0; j<p.length; j++)
 {
     p[j].setAttribute("onclick", "removeMe("+j+")");
 }


   Similar treatment we do with all "Click Me" buttons and text heading at cell zero in each row of the table. For putting a text content inside a span or td tag, we use "innerText" for IE and "textContent" functions for other browsers.


This way, we dynamically add/delete rows to HTML table element through JavaScript.

Tuesday, April 23, 2013

PHP Notes - II

1. Variable Functions :: Object methods can be called using variable names. Check out the below example.

<?php

class a
{
  public function disp($str)
  {
    echo "class a disp() says $str";
  }
}
$a  = new a;         /// Create Object
$new_func = "disp";  /// Assign function name to variable
$a->$new_func("DISPLAY");
?>


Output ::
class a disp() says DISPLAY

Explanation ::
$a->$new_func("DISPLAY") acutally calls $a->disp("DISPLAY"). Static functions can be called using variable functions as shown below.

<?php

class a
{
  static function disp()
  {
    echo "Static FN called";
  }
}
$new_func = "disp";  ///
Assign function name to variable
a::$new_func();      /// Now call the function using variable
?>


Output ::
Static FN called

Explanation ::
The function call a::$new_func() is converted to a::disp().

2. Some very interesting PHP functions ::
  
   a. If you want to know the list of extensions your PHP is using, write the following statement :
      <?php  print_r(get_loaded_extensions()); ?>
      This would list all the extensions like "Core", "zlib", "json", "xml", "mysql", "zip", "session", "curl", "soap", "ereg" etc.
  
   b. If you want to know the functions available with each extension, run the following statement :
      <?php print_r(get_extension_funcs("Core")); ?>
      This would list all functions "Core" extension offers, like "strlen", "strcmp", "each", "error_reporting", "func_num_args", "define", "function_exists", "create_function" etc.

      <?php  print_r(get_extension_funcs("mysql")); ?>
      This would list all functions "mysql" extension offers, like "mysql_connect", "mysql_close", "mysql_select_db", "mysql_query", "mysql_error", "mysql_affected_rows", "mysql_insert_id", "mysql_num_rows" etc.
  
   c. If you want to know the list of files included to the current script, run the statement below :
     
<?php print_r(get_included_files()); ?>
      This would show list of all files included to your script with the name of current script. If you do not have any script included, then the name of the current script is shown in the 0th position of the returned array. If other files are included, their names appear from 1st position onwards in the returned array.

   d. Always wanted to know about the makers of PHP? Run the statement below ..
     
<?php phpcredits (); ?>

   e. To get the OS info PHP is running on, type the statement below :
   
<?php     
    echo php_uname();
    echo "----------";
    echo PHP_OS;

    ?>


    Output ::
    Windows NT TEST-PC 6.1 build 7600 (Windows 7 Business Edition) i586
    ----------
    WINNT

3. Check out one example on PHP closures below ::

<?php
$p = 100;

/// Define the closure
$Hello['all'] = function() use ($p)
{
  echo "\$p = $p";
  $p++;
};

/// Call the function
$Hello['all']();

/// Print p
echo "\$p = $p";

?>


Output :
$p = 100
$p = 100

Some points need to be noticed in the example above.
a. If we don't use the "use ($p)" to the function definition, the anonymous function does not get access to variable $p in the parent scope.
b. The closure function tries to make changes to $p by calling $p++, but it does not changes $p in the parent scope which is evident when the second "echo" prints value of $p. If we want the closure function to get the true access to the $p in parent scope, we need to use reference in the function definition as shown below :

/// Define the closure
$Hello['all'] = function() use (&$p) //// Reference is used
{
  echo "\$p = $p";
  $p++;
};


Now, $p is incremented by 1 within the closure and hence, the second "echo" prints "$p = 101".

Friday, April 19, 2013

PHP Notes - I

Here I am discussing those small tidbits of PHP which we may not use in our PHP projects but they are very much part of core PHP. It is good to learn and remember them. I am discussing them point-wise below.

1. In PHP, variables containing Integer, Float, String or Boolean data are called Scalar variables. But variables with Null, Object, Resource or Array data won't be treated as scalar variable. We can test whether a variable is of scalar type by use of is_scalar() function.
 

<?php
$p = 100;
echo is_scalar($p);    // 1
echo is_scalar("");    // 1
echo is_scalar(false); // 1
?>

 

2. Conversion from other built-in types to objects creates stdClass objects. Check out the code below.
 

<?php
$v = (object)"standard";
var_dump( $v);
?>


Here one string ["standard"] has been converted to an Object. Check out the output below ::

object(stdClass)#1 (1) { ["scalar"]=> string(8) "standard" }

An object of built-in class stdClass is created on the fly, and its member called "scalar" holds the string "standard". Check out the another code snippet below.

<?php
$fp = fopen("test.txt", "r+");
$v = (object) $fp;
var_dump($v);
echo "<br>";
 

$v = (object) NULL;
var_dump($v);
echo "<br>";
 

$v = (object) array(1,2,3,4);
print_r($v);
?>


Output ::

object(stdClass)#1 (1) { ["scalar"]=> resource(3) of type (stream) }
object(stdClass)#2 (0) { }
stdClass Object
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
)


The first var_dump() shows that the typename of variable $fp (Resource) is stored in scalar member of stdClass object. The second var_dump() call shows an empty object when NULL was converted to object. However, this empty object does not result to be TRUE on echo empty($v); call. The print_r ($v) in the last line shows the object in array format. However we can not access each member in that object as $v->0 or $v->1 etc. Let's convert an associative array to object.

<?php
$v = (object) array("t1"=>1,"t2"=>2,"t3"=>3,"t4"=>4);
echo $v->t1 . $v->t2 . $v->t3 . $v->t4;
?>

Here, everything simply goes fine. Four members can be accessed as $v->t1, $v->t2, $v->t3, $v->t4.


3. Check out some predefined ("magic") constants used in PHP in program written below.

<?php
    class di_splay
    {
       public $name = 'Class One';
      
       function disp_lay()
       {
        echo "This PHP file is in Directory :: " . __DIR__ . "<br>";
        echo "This PHP file's full path :: " . __FILE__ . "<br>";
        echo "The name of this Function :: " . __FUNCTION__ . "<br>";
        echo "The name of this Class :: " . __CLASS__ . "<br>";
        echo "The name of this Method :: " . __METHOD__ . "<br>";
        echo "Curently Executing Line No. :: " . __LINE__ . "<br>";
       }
    }

   $di_splay = new di_splay;
   $di_splay->disp_lay();

?>


Output ::

This PHP file is in Directory :: C:\xampp\htdocs
This PHP file's full path :: C:\xampp\htdocs\test.php
The name of this Function :: disp_lay
The name of this Class :: di_splay
The name of this Method :: di_splay::disp_lay
Curently Executing Line No. :: 13

Hence the usage of constants like __DIR__, __FILE__, __FUNCTION__ is quite clear in the example above. I want to show another important point here ergarding __FILE__ constant. Check out the example below.

content of test.php ::
<?php
  ///// test.php
  include("include/test2.php");
   
  echo "This file names :: " . __FILE__ . "<br>";
  echo "This dir  names :: " . __DIR__ . "<br>";
?>


content of test2.php ::
<?php
  ///// test2.php

 
  echo "INCLUDED file names :: " . __FILE__ . "<br>";
  echo "INCLUDED dir  names :: " . __DIR__ . "<br>";
?>


Output :: 


INCLUDED file names :: C:\xampp\htdocs\include\test2.php
INCLUDED dir names :: C:\xampp\htdocs\include
This file names :: C:\xampp\htdocs\test.php
This dir names :: C:\xampp\htdocs

This clearly shows that __FILE__ and __DIR__ show filename and path of file in which they are contained. Though test2.php was included in test.php, __FILE__ in test2.php shows test2.php's properties.

Wednesday, April 17, 2013

Static Variables in PHP

1. Static variables should be declared as shown in the example below. Parse error would be raised if we assign an expressions to them.

<?php
function foo()
{
   static $i = 0;             // Valid
   static $j = $i + 10;       // Invalid as a expression is assigned
   static $j = loo($i + 10);  // Invalid as explained above
}

function loo($i)
{
  return $i * $i;
}
?>


2. Check the code below to see some more on static variables.

<?php
function foo()
{
   static $j = loo; 
   $j++;
   echo "<br>$j";
}
foo();
foo();
foo();
?>


Output :
Notice: Use of undefined constant loo - assumed 'loo' in C:\xampp\htdocs\test.php on line 4

lop
loq
lor

Note : the 'loo' is assumed to be a constant which was not defined earlier. Had it been defined before, the Notice would have gone away. Check the code below.

<?php
define("loo","A"); 
function foo()
{
   static $j = loo;  /// Constant can be assigned
   $j++;
   echo "<br>$j";
}
foo();
foo();
foo();
?>


Output :

B
C
D

Note : PHP characters behaved like integers in the code above; Actually the internal ASCII value is incremented/decremented like in C.

3. Inside a class, static variable can't be assigned with any constructor/function as shown in example below.

<?php
/// External Function
function foo()
{
  return 1;
}

//// Class Declaration
class One
{
    /// Initialize the static variable $var
    static $var = foo(); 

    /// Static function to retun static variable
    static function disp()
    {
       print ++ self::$var;
    }
}

One::disp();
One::disp();
One::disp();
?>


Output : An error message is shown.

Explanation : The statement static $var = foo(); is wrong, static variable can not be initialized with a function/constructor call. However the code can be written the following way to work properly.

<?php
/// External Function
function foo()
{
  return 1;
}

/// Static Variable Initialization, with 1 [returned by foo()]
One::$var = foo();

//// Class Declaration
class One
{
    /// Initialization of static variable is already done
    static $var; 

    /// Static function to return static variable
    static function disp()
    {
       print ++ self::$var;
    }
}

One::disp();  // Prints 2
One::disp();  // Prints 3
One::disp();  // Prints 4
?>


The code above is quite self-explanatory. We did an external initialization of static variable $var outside of the actual class definition. However this was possible because the static variable is was not declared as private. Check out the code below.

<?php
/// External Function
function foo()
{
  return 100;
}

class One
{
    ///// Private Static Member
    private static $var ;
   
    ///// Initialize Static Member against external functions
    static function init()
    {
      self::$var = foo();
    }
   
    /// Static function to retun static variable
    static function disp()
    {
        print ++ self::$var;
    }
}

One::init();  /// Initialize with 100
One::disp();  /// Prints 101
One::disp();  /// Prints 102
One::disp();  /// Prints 103
?>


Inheritance of static method is shown in the following example.

<?php
class one
{
    static protected $test = "class one";
    public static function static_test()
    {
       echo self::$test ;
    }
}

class two extends one
{
    //// This has to be static, otherwise re-declaration error occurs
    static protected $test = "class two";
}

two::static_test(); /// class one
?>


In this example, self:: is resolved using the class in which the method belongs. "this" can't be used inside a static method. The static_test() function does not exist in class two, but in class one. Hence "class one" is printed ... this is a limitation of self:: ... kind of "Early Binding" effect in C++. To get the effect of "Late Binding", we need to change the line

echo self::$test ;

to

echo static::$test ; /// This calls for Late Static Binding

As a result, "class two" is printed. But the construct "static::" can only be used with static properties. Another example where a different approach for accessing static properties is shown..


<?php
class Foo
{
   // Define static property

   public static $my_static = 1;
}
 

// Inheritance
class Bar extends Foo
{

}

// Parent Object

$foo = new Foo();
print $foo::$my_static; // 1
 

// Increment
$foo::$my_static ++;

// Child Object

$boo = new Bar();
print $boo::$my_static; // 2
?>


The program above access static properties using object. All the following constructs access the same static property..

echo Foo::$my_static;  // Class Name used
echo Bar::$my_static;  // Class Name used
echo $boo::$my_static; // Object used

Invoking static property of any abstract class is also possible.
<?php
abstract class Foo
{
    public static $bar = "100";
}
echo  ++Foo::$bar ; // prints 101

?>

HTML Form Submission

Check out some notes on HTML forms which I think is very useful.

1. If we use a form like this ::

<form name='f' action = "test.php?id=123&color=blue" method='GET'>
<input type='text' name='fname'>
<input type='submit' name='btn_submit' value='submit'>
</form>


the form is submitted to URL :: test.php?fname=john&btn_submit=submit (though the action is set to test.php?id=123&color=blue)The pre-defined URL parameters "id" and "color" are overwritten. Hence the "id" and "color" are never captured at the Server end. 


But if we change the method to "POST", all the four parameters ("id", "color", "fname" and "btn_submit") are captured. PHP $_GET global variable receives "id", "color", $_POST gets "fname" and "btn_submit" parameters while $_REQUEST receives all fours of them.

2. If we use Image Submit buttons and suppose that element has a name 'submit_btn', we would receive two element's values at the server end. This is shown below.
 

<?php
if(!empty($_GET))
    print_r( $_GET );
?>


<form name='f' method='GET'>
Enter your name <input type='text' name='c_name'>
<input type='image' name='btnsubmit' src='images/submit_btn.jpg'>
</form>


The above form consists of an input text element and another input element with type image. The second element works as a Submit button. When we submit the form, the URL becomes quite similar to this ...

http://127.0.0.1/test.php?c_name=&btnsubmit.x=2&btnsubmit.y=1

The btnsubmit.x and btnsubmit.y captures the co-ordinates on the Submit buttons's image where the click occurred. If you make the input element like this (remove the name attribute from the element itself) ::

<input type='image' src='images/submit_btn.jpg'>

the URL would become ::

http://127.0.0.1/test.php?c_name=cder&x=0&y=0

See that btnsubmit.x has been changed to only x and btnsubmit.y has been changed to only y.

3. Check and following code :

<html>
<body>
<!-- SCRIPT STARTS -->
<script type='text/javascript'>
function f_name(fname)
{
  document.f.fname.value = fname;
  document.f.submit();
 
}
</script>
<!-- SCRIPT ENDS -->

<!-- FORM STARTS -->
<form name='f' >
<input type='text' name='fname' placeholder="Enter your first name">
<input type='submit' name='submit' value='submit'>
</form>
<!-- FORM ENDS -->

I am <a href='javascript:;' onclick="f_name('Michael')">Michael</a> | <a href='javascript:;' onclick="f_name('John')">John</a> | <a href='javascript:;' onclick="f_name('Ramon')">Ramon</a>

</body>
</html>


The form looks like the pic below.





The form can be submitted two ways,
a. Enter your first name in the textbox given and hit the Submit button
b. Click on any one of the 3 links given at the bottom. This calls up the Javascript function f_name() which then submits the form though the statement ::
   document.f.submit();

But wait, it gave an error message?

...















"document.f.submit is not a function". 

This is a very common error I have seen while working with various web-forms.

The reason :: We can access all the elements inside a form as shown below.

document.form_name.element_name

example :


//// Changes value of 'fname' element within the form names 'f'
document.f.fname.value = "John";  

Similarly, we can access the Submit button in the form above ::

//// This would change the Button text
document.f.submit.value = 'Hit Me !!!'

"submit" is the name of that Submit button input element. Hence, when we try to submit the form by calling document.f.submit() in the f_name() function, the Javascript engine identifies that it is name of an element existing within the form, hence it shows an error message which causes the form not to be submitted at all.

Solution :: Simply renaming the submit button to anything other than 'submit' would do. Even 'Submit' [S is in caps] makes it working as Javascript, being case-sensitive, distinguishes "Submit" to be different from "submit". Hence document.f.submit(); submits the form without any hassle as the submit button element has now been accessible with :: document.f.Submit  (S is in caps).

Tuesday, April 16, 2013

Print Pascal's Triangle in PHP

Pascal's triangle is named after French mathematician Blaise Pascal. More info on this triangle can be found here. In this triangle, from 3rd row onwards, each number in the triangle is the sum of the two numbers appearing immediately above it. A small triangle is shown below.

                    1
                  1   1
                1   2   1
              1   3   3   1
            1   4   6   4   1
         1   5   10   10   5   1
       1   6   15   20   15   6   1
     1   7   21   35   35   21   7   1



How we try to solve this problem?

a. For the first row, we don't put a logic.
b. For 2nd row, we create an array of two ones. Then we print it.
c. For 3rd row onwards, we calculate sum of 2 digits appearing in the previous row.
   For 3rd row :: we create an array, set the first and last elements in the array to 1. Then we sum taking each 2 elements in the previous row i.e the array available in 2nd row. We start doing this sum from element index 1.
   For 4th row :: we create an array, set the first and last elements in the array to 1. Then we sum taking each 2 elements in the previous row i.e the array available in 3rd row.
   .... and so on till the total number of lines we are asked to print.
  
Check the code below which is quite self-explanatory.

<?php
//// Define Total Lines of the Pyramid
$total_lines = 10;

//// Define a Base Array
$base_arr = array(1,1);

//// PRINT LINE 1
pri_nt(1);

//// PRINT LINE 2
pri_nt(2, $base_arr);

//// Main LOOP to print from Line 3 onwards
for($i=3;$i<=$total_lines-2;$i++)
{
  //// CREATE ARRAY
  $arr = range(1,$i);
 
  //// Set 1st & Last item set to 1
  $arr[0] = $arr[count($arr)-1] = 1; 
 
  //// Get Previous Row's Array values for summation
  //// We start with index 1, zeroth element always holds 1
  for( $k=1; $k<count($arr)-1; $k++)
  {
    $arr[$k] = $base_arr[$k] + $base_arr[$k-1];
  }
 
  //// PRINT the new ARRAY
  pri_nt( $i, $arr );
 
  //// Preserve Current Array
  $base_arr = $arr;
}

function pri_nt( $cur_line, $arr = "" )
{
  global $total_lines;
 
  //// Printing Logic for 2nd Line Onwards
  if( is_array( $arr ) && !empty($arr) )
  {
     //// PRINT SPACES
     for( $i=1; $i<($total_lines-$cur_line)*2; $i++)
       echo "&nbsp;";
   
     //// PRINT DIGITS
     for( $i=0; $i<count($arr); $i++)
       echo "
&nbsp;&nbsp;&nbsp;" . $arr[$i] . "";
    
     //// New Line
     echo "<br>";
  }
  else   //// PRINT the ONE star at LINE 1
  {
    
     //// PRINT Spaces
     for( $i=1;$i<($total_lines-$cur_line)*2; $i++)
       echo "
&nbsp;";
   
     //// PRINT DIGIT 1
     echo "
&nbsp;&nbsp;&nbsp;"."1";
   
     //// New Line
     echo "<br>";   
  }

}
?>

Print ASCII in PHP

Printing ASCII characters in PHP is easy. However various browsers would render the characters differently on the screen. Check the code below.

<?php
for($i=0;$i<=255;$i++)
{
  $b = chr($i);
  echo "<br>($i) :: [$b]";
}
?>


The above code would generate the output as shown in the picture at right::


...

Here is the output I noticed on various browsers.

Opera 12.15  :: Showed all characters
IE 8 :: Showed characters ranging 0-127, 128 onwards showed character '�' instead.
Safari 5.1.7 :: Did not show characters ranging 0-31 only [9,10,13 excluded]
Firefox 19 :: Did not show characters ranging 0-31 [9,10,13 excluded], and 128 onwards showed a question mark instead. UTF-8 encoding was enabled though.
Chrome 26.0.1410.64 m :: Did not show characters ranging 0-31 [9,10,13 excluded]

I changed the Line 4 as shown below ...

echo "<br>($i) :: [$b] [&#$i;]";

Check the output below :: [As shown in Firefox, Firefox now can show characters 128 onwards]

(123) :: [{] [{]
(124) :: [|] [|]
(125) :: [}] [}]
(126) :: [~] [~]
(127) :: [] []
(128) :: [€] [�]
(129) :: [] [�]
(130) :: [‚] [�]
(131) :: [ƒ] [�]
(132) :: [„] [�]
(133) :: […] [�]
(134) :: [†] [�]
(135) :: [‡] [�]
(136) :: [ˆ] [�]

Note : If the number is higher than 255, it would give the number % 256. Which means the statement :

echo chr(256);

would render zero ... 256 % 256 = 0

HTML characters related stuffs available at Bob Baumel's Page

How to read a file backward in PHP?

Reading backward means, suppose a text file has 25 lines; and we want to read that file starting from line 25th fist, then line no. 24, then 23rd, 22nd and so on till line number 1.

Check the logic below to achieve this goal. Each line in a text file has a particular position within the file.

a. Start reading the file from the beginning (position zero) and store the current file pointer position into an array. This way, we would store the position of all the lines (starting position) in that array.
b. When reading is complete, we iterate the array backward.
c. For each iteration of that array, we put the file pointer pointing to the array value i.e starting position of a line.

d. Then we read that line and print on screen.

Now check the PHP implementation below.
 

<?php
//// OPEN FILE
$filename = "car_names.txt";
$fp = fopen($filename,"r+")
or
die("Could not open file :: " . error_get_last()['message'] );

//// Create an array to store various positions in the file
$line_beg = array(0);  ///// First line is at position 0

//// Run the loop for reading the file from beginning
while( ($buffer = fgets($fp,80))!== false )
{
  //// Store the starting position of each line to the array
  $line_beg[] = ftell( $fp );   


//// Start iterating the Array backward
for($i = count($line_beg)-1; $i >=0; $i--)
{
  //// Move the file pointer to desired location
  fseek($fp, $line_beg[$i] );
  

  //// Read that line
  $buffer = fgets($fp, 80 );
  if( trim($buffer) != "" )
  {
      //// Print the line
      echo "Line : $i, Content : $buffer<br>";
  }

}

//// Close file
fclose ($fp);
?>


Note :
1. error_get_last() holds various Error related info in array format, hence error_get_last()['message'] points to 'message' key of that array which contains the whole Error message. The whole array looks like as shown below in case the file car_names.txt was not opened successfully ::
 

Array
(
    [type] => 2
    [message] => fopen(car_names.txt): failed to open stream: No such file or directory
    [file] => C:\xampp\htdocs\test.php
    [line] => 2
)


2. $line_beg = array(0);
We initialized the array with the beginning of the first line (position zero)

The code above was really too big when we can do it in only four lines as shown below.

<?php
//// Read Content, create array of all lines in the file
$file = file("$filename");   
//// Reverse the Array
$file = array_reverse($file);
//// Iterate and Print
foreach($file as $f)
{
    echo $f."<br />";
}
?>