Brought to you by molecularsciences.org.
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 License.
This publication may not be redistributed without this notice.

PHP

Some PHP articles.

Manipulating XML with PHP

XML is a markup language created to facilitate communication between different systems. Most implementations of XML serve to facilitate machine-to-machine communication.

Document Object Model (DOM) is an API which defines the logical structure and the ways to access and manipulate XML documents. XML presents data as documents. DOM is used to access and manipulate the data in XML documents.

Programming languages us an API to access XML. PHP provide excellent support for DOM, SAX, and SimpleXML, all three of whom are widely used API. As of PHP5, all XML extensions are based on the libxml2. libxml2 is an excellent library that greatly simplifies the lives of developers by allowing interoperability between different XML-related extensions. PHP5 provides excellent support for SAX, DOM, and SimpleXML.

SAX and DOM
The most important simplified difference between SAX (Simple API for XML) and DOM (Document Object Model) is that SAX reads line by line while DOM creates a document tree. Generally, SAX is more efficient than DOM for small XML files. As a rule of thumb, if your XML files are complex or more than a few pages long, use DOM.

This article would primarily cover manipulating XML documents with SAX and DOM in PHP.

Manipulating XML with SimpleXML

SimpleXML is a SAX XML parser. It represents an XML document as a hierarchical set of objects and properties where each element is an object and each attribute is an object property.

Access an XML element using SimpleXML

<?xml version='1.0'?>
<hotels>
    <hotel stars="5">
        <name>President Wilson</name>
        <city>Geneva</city>
        <country>Switzerland</country>
    </hotel>
</hotels>

Save this file as hotel.xml

// load XML file
$xml = simplexml_load_file('hotel.xml') or die ("Unable to load XML");
    
// access xml element
echo 'Hotel: ' . $xml->hotel->name;

Note that we did not have to call the tag "hotels" since it is the root.

Accessing multiple XML elements using SimpleXML

<?xml version='1.0'?>
<hotels>
    <hotel stars="5">
        <name>President Wilson</name>
        <city>Geneva</city>
        <country>Switzerland</country>
    </hotel>
    <hotel stars="5">
        <name>Montreux Palace</name>
        <city>Montreux</city>
        <country>Switzerland</country>
    </hotel>
    <hotel stars="3">
        <name>Express by Holiday Inn</name>
        <city>Geneva</city>
        <country>Switzerland</country>
    </hotel>        
</hotels>

Save this file as hotels.xml

// show how to access multiple elements with SimpleXML
    
// load XML file
$xml = simplexml_load_file('hotels.xml') or die ("Unable to load XML");
    
// access XML elements
foreach ($xml->hotel as $hotel)
{
    // print data
    print '<br>Hotel: ' . $hotel->name;
}
    
// count elements
print '
Total: ' . count($xml->hotel);

The foreach loop iterates over the XML elements. count() function allows users to count any type of element.

Accessing attributes of XML elements
SimpleXML stores attributes as key value pairs in an associative array.

// accessing attributes of xml elements
    
// load XML file
$xml = simplexml_load_file('hotels.xml') or die ("Unable to load XML");
    
// access XML elements
foreach ($xml->hotel as $hotel)
{
    // print data
    print '<br>' . $hotel->name . ' is a ' . $hotel['stars'] . ' star hotel';
}

Altering XML element and attribute values
This simple example shows how to change XML element and attribute values:

// alter xml elements and attributes using SimpleXML
    
// load XML file
$xml = simplexml_load_file('hotels.xml') or die ("Unable to load XML");
    
// change element value
$xml->hotel[2]->name = 'Crown Plaza';
    
// change attribute value
$xml->hotel[2]{'stars'} = 4;
    
// print new XML string
header('Content-Type: text/html');
echo $xml->asXML();

The asXML() function converts SimpleXML object tree to XML. Following is the output of this program

<?xml version="1.0"?>
<hotels>
    <hotel stars="5">
        <name>President Wilson</name>
        <city>Geneva</city>
        <country>Switzerland</country>
    </hotel>
    <hotel stars="5">
        <name>Montreux Palace</name>
        <city>Montreux</city>
        <country>Switzerland</country>
    </hotel>
    <hotel stars="4">
        <name>Crown Plaza</name>
        <city>Geneva</city>
        <country>Switzerland</country>
    </hotel>        
</hotels>

Note that this program only printed an edited XML string to screen, it did not edit the XML file. To edit the XML file, you need to rewrite the entire file.

Creating XML Document with DOM

As we go through the articles, we would be build a small library of functions which would prove to be very handy when you would start XML development.
php_dom_xml_library.php

function createFile()
{
    // create new dom document
    $xml = new DOMDocument();
    
    // save dom document to an xml file
    $xml->save('out.xml');
}

// call xml function
createFile();

output:

<?xml version="1.0"?>

This very simple two line code creates and saves and XML file. The first line creates a new DOM document. The second line saves the DOM document to an XML file.

Next, we add a root element to the DOM and save it in our XML file.
php_dom_xml_library.php

function createFile()
{
    // create new dom document
    $xml = new DOMDocument();
    
    // these lines would create a nicely indented XML file
    $xml->preserveWhiteSpace = false;
    $xml->formatOutput = true;
    
    // create a root element
    $root = $xml->createElement("phonebook");
    
    // add root to DOM document root
    $xml->appendChild($root);
        
    // save dom document to an xml file
    $xml->save('out.xml');
}

// call xml function
createFile();

output:

<?xml version="1.0"?>
<phonebook/>

By default the entire XML document is saved as one long string. To generate a more readable document, we need to set preserveWhiteSpace to false and formatOutput to true as in the second and third lines of code. First we create and DOM element called phonebook, then we append it to the DOM document.

Let's add a few more elements to the XML document.
php_dom_xml_library.php

function createFile($xml_file)
{
    // create new dom document
    $xml = new DOMDocument();
    
    // these lines would create a nicely indented XML file
    $xml->preserveWhiteSpace = false;
    $xml->formatOutput = true;
    
    // create a root element, and add it to DOM
    addRoot($xml);
    
    // add more elements to xml file
    $friend = $xml->createElement("friend");
    
    // add this element to the root
    $xml->documentElement->appendChild($friend);
    
    // create two more elements
    $name = $xml->createElement("name");
    $phone = $xml->createElement("phone");
    
    // append these elements to friend
    $friend->appendChild($name);
    $friend->appendChild($phone);
        
    // save dom document to an xml file
    $xml->save($xml_file);
}

function addRoot(&$xml)
{
    $xml->appendChild($xml->createElement("phonebook"));
}

// call xml function
createFile('out.xml');

output:

<?xml version="1.0"?>
<phonebook>
  <friend>
    <name/>
    <phone/>
</phonebook>

In this code, I have simple moved the code to create the root to another function. createFile() now take XML filename as a parameter. The important lines are between addRoot() and $xml->save(). documentElement refers to the root element. To add an element to the XML file, we need to create it and then append it to another node. The last two lines before xml_save append the created elements to the element friend.

So far, we have only been creating tags. Time to add text to the tags.
php_dom_xml_library.php

function createFile($xml_file)
{
    // create new dom document
    $xml = new DOMDocument();
    
    // these lines would create a nicely indented XML file
    $xml->preserveWhiteSpace = false;
    $xml->formatOutput = true;
    
    // create a root element, and add it to DOM
    $root = $xml->appendChild($xml->createElement("phonebook"));
    
    // create element and add to root
    $friend = $xml->createElement("friend");
    $xml->documentElement->appendChild($friend);
    
    // create elements
    $name = $xml->createElement("name");
    $phone = $xml->createElement("phone");
    
    // append elements to friend
    $friend->appendChild($name);
    $friend->appendChild($phone);
    
    // add text to elements
    $name->appendChild($xml->createTextNode("Alice"));
    $phone->appendChild($xml->createTextNode("123-456-7890"));
        
    // save dom document to an xml file
    $xml->save($xml_file);
}

// call xml function
createFile('out.xml');

output:

<?xml version="1.0"?>
<phonebook>
  <friend>
    <name>Alice</name>
    <phone>123-456-7890</phone>
</phonebook>

Text has to be added to DOM as a node. To add text, we use createTextNode() function and append it to a DOM element.

Next we add attributes to an XML file
php_dom_xml_library.php

function createFile($xml_file)
{
    // create new dom document
    $xml = new DOMDocument();
    
    // these lines would create a nicely indented XML file
    $xml->preserveWhiteSpace = false;
    $xml->formatOutput = true;
    
    // create a root element, and add it to DOM
    $root = $xml->appendChild($xml->createElement("phonebook"));
    
    // create element and add to root
    $friend = $xml->createElement("friend");
    $xml->documentElement->appendChild($friend);
    
    // create elements
    $name = $xml->createElement("name");
    $phone = $xml->createElement("phone");
    
    // append elements to friend
    $friend->appendChild($name);
    $friend->appendChild($phone);
    
    // add text to elements
    $name->appendChild($xml->createTextNode("Alice"));
    $phone->appendChild($xml->createTextNode("123-456-7890"));
    
    // add attributes
    $phone_attr1 = $xml->createAttribute("type");
    $phone_attr1->appendChild($xml->createTextNode("cell"));
    $phone_attr2 = $xml->createAttribute("country_code");
    $phone_attr2->appendChild($xml->createTextNode("1"));
    $phone->appendChild($phone_attr1);
    $phone->appendChild($phone_attr2);
        
    // save dom document to an xml file
    $xml->save($xml_file);
}

// call xml function
createFile('out.xml');

output:

<?xml version="1.0"?>
<phonebook>
  <friend>
    <name>Alice</name>
    <phone type="cell" country_code="1">123-456-7890</phone>
</phonebook>

PHP Arrays

Following are selected articles on array manipulation using PHP

Accessing last element in a PHP array

Since PHP array are indexed from 0, the last element at any given time has the index count of array minus one. Following is a code example:

// accessing last element in an array
$a = array('adam', 'bob', 'cathy');
print $a[count($a) - 1];

The output of this code is:

cathy

Passing arrays by value and reference

The difference between passing by value and passing by reference is that you when pass by value, you are passing a copy of the array. When passing by reference, you are passing a pointer i.e any changes made in the function you pass to can modify the original.

function foo($var)
{
    $var[1]++;
}
function bar(&$var)
{
    $var[1]++;
}

$a=array(5,6,7);
foo($a);
print "Passed by value:\n";
print_r($a);
bar($a);
print "Passed by reference:\n";
print_r($a);

output

Passed by value:
Array
(
    [0] => 5
    [1] => 6
    [2] => 7
)
Passed by reference:
Array
(
    [0] => 5
    [1] => 7
    [2] => 7
)

When passed by value, elements of $a remain unchanged. When passed by reference, the second element of $a changed. The only difference in code is the & in the function parameter.

Removing a element from an array

To remove an element from an array, we use array_splice().

$arr = array("red", "green", "blue", "black");
print_r($arr);
for ($i = 0; $i < count($arr); $i++) {
  if ($i == 2) {
    array_splice($arr, $i, 1);
  }
}
print_r($arr);

The element blue has been removed from the array.

Array
(
    [0] => red
    [1] => green
    [2] => blue
    [3] => black
)
Array
(
    [0] => red
    [1] => green
    [2] => black
)

Caution about using array_splice() in a loop

$arr = array("red", "green", "blue", "black");
print_r($arr);
for ($i = 0; $i < count($arr); $i++) {
  print $arr[$i] . ' ';
  if ($arr[$i] === "blue") {
    array_splice($arr, $i, 1); $i--;
  }
  print $arr[$i] . "\n"; 
}
print_r($arr);

Output

Array
(
    [0] => red
    [1] => green
    [2] => blue
    [3] => black
)
red red
green green
blue green
black black
Array
(
    [0] => red
    [1] => green
    [2] => black
)

The moment we remove an element with an array_splice, the next element becomes the current element. If we continue looping, we would skip the next element. The solution is to decrement the index by one, making previous element the current element. Accessing the current element at this point would mean accessing the previous element. Thus decrement must be followed by continue statement as follows:

$arr = array("red", "green", "blue", "black");
print_r($arr);
for ($i = 0; $i < count($arr); $i++) {
  print $arr[$i] . ' ';
  if ($arr[$i] === "blue") {
    array_splice($arr, $i, 1); 
    $i--;
    print "\n";
    continue;
  }
  print $arr[$i] . "\n"; 
}
print_r($arr);

Removing duplicates values from an array

The array_unique function removes duplicates from an array.

$aSample = array(1,1,6,6,6,8,"8");
print_r(array_unique($aSample));

output

Array
(
    [0] => 1
    [2] => 6
    [5] => 8
)

By default all values are compared as strings, thus there is no difference between 8 and "8".

Removing quotes - a step by step example of manipulating array data

This article discusses some techniques of manipulating data in an array. To keep it simple, let's start by looking how we can remove quotes from a variable. To remove a character, we can replace it with nothing using str_replace() function.

$a = "'pineapple'";
$b = '"guava"';
print "$a $b\n";
$a = str_replace("'","",$a);
$b = str_replace('"','',$b);
print "$a $b\n";

This results in:

'pineapple' "guava"
pineapple guava

Suppose we need to be perform this operation on every element of the array. The logical place to start would be to use a foreach loop.

print "original\n";
$fruits = array("'apple'","'banana'","'nectar'");
print_r($fruits);

print "Using foreach\n";
foreach ($fruits as $fruit) { $fruit = str_replace("'","",$fruit); }
print_r($fruits);

Unfortunately this does not work as the variable $fruit is temporary variable which holds a copy of the given element. Modifying the value of this$fruit does not modify the value of the desired element in the array.

original
Array
(
    [0] => 'apple'
    [1] => 'banana'
    [2] => 'nectar'
)
Using foreach
Array
(
    [0] => 'apple'
    [1] => 'banana'
    [2] => 'nectar'
)

Let's try this with a for loop.

print "original\n";
$fruits = array("'apple'","'banana'","'nectar'");
print_r($fruits);

print "Using for loop\n";
for ($i = 0; $i < count($fruits); $i++) {
  $fruits[$i] = str_replace("'","",$fruits[$i]);
}
print_r($fruits);

Pretty self-explanatory. Loop through the array, extract each element, remove quotes and replace the original element in the array with this one.

original
Array
(
    [0] => 'apple'
    [1] => 'banana'
    [2] => 'nectar'
)
Using for loop
Array
(
    [0] => apple
    [1] => banana
    [2] => nectar
)

Very often we are interested in performing more complex manipulations than simply removing codes. In such cases, it is a good idea to delegate the work to a function.

function strip_single_quotes($value)
{
  return str_replace("'","",$value);
}
print "original\n";
$fruits = array("'apple'","'banana'","'nectar'");
print_r($fruits);

print "Using for loop by value\n";
for ($i = 0; $i < count($fruits); $i++) {
  $fruits[$i] = strip_single_quotes($fruits[$i]);
}
print_r($fruits);

strip_single_quotes() is called by value, meaning that strip_single_quotes() receives a copy of the the array element. strip_single_quotes() removes quotes from this copy and returns the modified copy. This copy then replaces the array element. The result of this program:

original
Array
(
    [0] => 'apple'
    [1] => 'banana'
    [2] => 'nectar'
)
Using for loop by value
Array
(
    [0] => apple
    [1] => banana
    [2] => nectar
)

Another way to accomplish the same is by sending a reference rather than a copy to the function.

function remove_single_quotes(&$value)
{
  $value = str_replace("'","",$value);
}

print "original\n";
$fruits = array("'apple'","'banana'","'nectar'");
print_r($fruits);

print "Using for loop by reference\n";
for ($i = 0; $i < count($fruits); $i++) {
  remove_single_quotes($fruits[$i]);
}
print_r($fruits);

Here we send a reference (address of) the array element. Note the &$ in remove_single_quotes(). As remove_single_quotes() operates on the original element, there is no need to return a value. The output:

original
Array
(
    [0] => 'apple'
    [1] => 'banana'
    [2] => 'nectar'
)
Using for loop by reference
Array
(
    [0] => apple
    [1] => banana
    [2] => nectar
)

A nicer way to accomplish the same is by using array_walk() instead of a loop. array_walk() iterates through an array apply a function to each element of the array.

function remove_single_quotes(&$value)
{
  $value = str_replace("'","",$value);
}

print "original\n";
$fruits = array("'apple'","'banana'","'nectar'");
print_r($fruits);

print "Using array_walk\n";
array_walk($fruits,'remove_single_quotes');
print_r($fruits);

The output:

original
Array
(
    [0] => 'apple'
    [1] => 'banana'
    [2] => 'nectar'
)
Using array_walk
Array
(
    [0] => apple
    [1] => banana
    [2] => nectar
)

Comments?

File management with PHP

Following articles are about creating, managing and manipulating data from files.

Copying and renaming files

To copy files, use the copy() function. To rename files, use the rename() function.

$oldfile = 'file.txt';
$newfile = 'file2.txt';
copy($oldfile, $newfile);
rename($newfile,'file3.txt');

copy() will create a new file if it does not exist. If it exists, copy() would delete its contents.

Counting lines in a text file

The following simple code count the number of lines in a text file.

public function countLinesInTextFile($address)
{
    return count(file($address));
}
print countLinesInTextFile('file.txt');

Deleting file contents

To delete file contents and not the file, open the file in write mode and close is without writing anything.

$fh = fopen("file.txt", 'w');
fclose($fh);

Displaying directory contents

For security reasons, most servers on the Internet do not show the contents of a directory if the directory address is typed. The user is either redirected to index.whatever, a default page, page not found or access denied. Thus the list of files in the directory are not displayed.

If you need to show the contents of your directory, you can use the following code:

<?php
exec("ls", $output, $return);
foreach ($output as $file )
if ($file != "index.php") { print "<a href='$file'>$file</a><br>"; }
?> 

If exec() is blocked by your server due to SELinux settings, you can use proc_open() instead.

You can also use the opendir() in PHP if you have sufficient permissions on a given directory.

<?php
$dir = opendir("my_dir") or die ('Cannot open directory');
while (($file = readdir($dir)) != false) {
    print $file . '<br>';
}
?> 

If you only want to list files with a certain extension, use the following code:

<?php
$dir = opendir("my_dir") or die ('Cannot open directory');
while (($file = readdir($dir)) != false) {
    // only list text files
    if (preg_match("/txt$/", $file)) {
        print $file . '<br>';
    }
}
?> 

Getting filesize of a file

filesize function returns size of a file in bytes.

$f = 'files/debug.log';
echo filesize2bytes(filesize($f));

is_dir not working

The is_dir() function in PHP allows users to check whether a file is a directory. It returns true if the file is a directory. However, the addresses provided must be RELATIVE TO THE CURRENT DIRECTORY. Suppose we have a directory structure as follows:

cwd
|-- dir1
     |-- dir2
          |-- dir3

where cwd is the current working directory

is_dir(dir1);  // returns true
is_dir(dir2);  // returns false
is_dir(dir1/dir2);  // returns true

Reading file contents to an array and string

PHP allows you to easily read your file contents into an array or a string. To read into a string, use file_get_contents() function. To read into an array, use file() function. The file function would copy each line of content into a different array element.

Grocery List

bread
eggs
milk

grocery_list.txt

PHP code

file() returns contents of file as array
file_get_contents() returns contents of file as string
Array ( [0] => bread [1] => eggs [2] => milk )
bread eggs milk 

<?php
    $afile = file('grocery_list.txt');
    $sfile = file_get_contents('grocery_list.txt');
    print '<br>file() returns contents of file as ' . gettype($afile);
    print '<br>file_get_contents() returns contents of file as ' . gettype($sfile);
    print '<br>';
    print_r($afile);
    print '<br>';
    print_r($sfile);
?>

grocery_list.php

Output

file() returns contents of file as array
file_get_contents() returns contents of file as string
Array ( [0] => bread [1] => eggs [2] => milk )
bread eggs milk 

Reading from file

Following is the text file we need to read:

users
user
uid
name|datatype|string
login|datatype|string
password|datatype|string

The following code reads the file, picks up relevant data and creates and SQL query.

// read file content into an array
$file = file('users.def');
    
// create an SQL query 
$sql = 'create table ' . $file[0] . ' ( '
     . $file[2] . ' serial primary key ';
    
// loop through name|datatype|string
for ($i = 3; $i < count($file); $i++) {
    // split by | and store data in an array
    $fields = preg_split("/\|/", $file[$i]);
    $sql .= ', ' . $fields[0];
        
    // compare string
    if (trim($fields[2]) === "string") { 
        $sql .= ' varchar(100) '; 
    } else { 
        $sql .= ' int '; 
    }
        $sql .= ' not null ';
    }
$sql .= ');';
print $sql;

file() function converts file contents into an array where each line can be accessed by an index (the line number). Next we split the line on some symbol, space in this case.

Uploading files

To upload a file into your web server, you need to create a directory where your files should reside. It should not be a directory where you store your php, html, css, etc files. Assign write all permissions to the directory. In Unix:

mkdir uploads
chmod 777 uploads

The next step is to create an HTML form

<html>
<body>
<form enctype="multipart/form-data" action="getfile.php" method="POST">
Please upload your dta file: <input name="uploaded" type="file" /><br />
<input type="submit" value="Upload" />
</form>
</body>
</html>

Save this file as form.php

The next step is to create an upload file as follows:

<?php
$target = "uploads/";
$target = $target . basename( $_FILES['uploaded']['name']) ;
if(move_uploaded_file($_FILES['uploaded']['tmp_name'], $target)) {
  echo "The file ". basename( $_FILES['uploadedfile']['name']). " is uploaded";
} else {
  echo "Could not upload your file.";
}
?>

Name this file getfile.php and run main.php. That'a all!

Writing to file

The following code writes a string to a file called out.txt inside the data directory:

$f = "data/out.txt";
$fh = fopen($f, 'w') or die("can't open file");
$sData = "Some text\nmore text";
fwrite($fh, $sData);
fclose($fh);

This would overwrite contents of out.txt. To append to out.txt, use fopen($f, 'a').

Make sure that Apache has write permissions to the data directory.

PHP and SQL

Following articles concern PHP with MySQL and PostgreSQL

Connecting PHP with MySQL

Connecting to MySQL with PHP is very simple. Following is a sample table and script:

+----+--------+-------+
| id | make   | model |
+----+--------+-------+
|  1 | toyota | camry |
|  2 | toyota | rav4  |
|  3 | honda  | crv   |
+----+--------+-------+

  1 <?php
  2   $host = 'localhost';
  3   $user = 'titanic1912';
  4   $pass = 'lusitania1916';
  5   $db = 'cars';
  6   $conn = mysql_connect($host, $user, $pass) or die ('Could not connect to db');
  7   mysql_select_db($db) or die ('could not select db');
  8   $q = 'select * from cars';
  9   $rs = mysql_query($q);
 10   while($rw = mysql_fetch_object($rs))
 11   {
 12     print $rw->toyota . ' ' . $rw->model . '
'; 13 } 14 mysql_close($conn); 15 ?>

Line 6 connects to the mysql database. In line 7, we select our desired database. Line 9 runs the query. Line 10 fetches the results from the query and line 12 prints the results. Line 14 closes the connection.

If you are a beginner, substitute your own values from line 2 to 5. Then modify the query in line 8. Finally edit line 12 to perform your desired task.

Listing MySQL tables, columns, and row count using PHP

Listing all table in a MySQL database

mysql_connect("localhost","user","pass") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());

$rs = mysql_query("show tables") or die(mysql_error());  
while($row = mysql_fetch_array($rs)) 
{ 
    print '<br>' .  $row[0]; 
}

Counting rows in a table

mysql_connect("localhost","user","pass") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());

$rs = mysql_query("select * from TABLE-NAME") or die(mysql_error());  
print mysql_num_rows($rs);

Counting fields in a table

mysql_connect("localhost","user","pass") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());

$rs = mysql_query("select * from TABLE-NAME") or die(mysql_error());  
print mysql_num_fields($rs);

List column names in a table

mysql_connect("localhost","user","pass") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());

$rs = mysql_query("select * from TABLE-NAME") or die(mysql_error());  
$count = mysql_num_fields($rs);
for ($i = 0; $i < $count; $i++)
{
    print mysql_field_name($rs,$i) . '<br>';
}

Columns are list in the same order as they are listed in the table.

List tables names and row count

mysql_connect("localhost","user","pass") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());

print '<table>';
$rs = mysql_query("show tables") or die(mysql_error());  
while($rw = mysql_fetch_array($rs)) 
{ 
    $query = "select * from " . $rw[0];
    $rs2 = mysql_query($query) or die(mysql_error());
    $count = mysql_num_rows($rs2);
    
    print '<tr><td>' . $rw[0] . '</td><td>' . $count . '</td></tr>';
}
print '</table>';

Listing tables and column names of PostgreSQL with PHP

$sHost = 'localhost';
$sDatabase = 'aaaa';
$sUser = 'bbbb';
$sPass = 'cccc';

$conn = pg_connect("host=$sHost dbname=$sDatabase user=$sUser password=$sPassword") 
    or die('unable to connect to database');
$q = 'select relname from pg_stat_user_tables order by relname';
$result = pg_query($conn, $q) or die ("Error in query: $q - ' . pg_last_error($q));        

while ($row = pg_fetch_array($result))
{
    print $row[0] . '<br>';
    $q2 = 'select * from ' . $row[0];
    $rs = pg_query($conn, $q2) or die ("Error in query: $q2 - ' . pg_last_error($q2)); 
    $i = 0;
    while ($i < pg_num_fields($rs))
    {
        $fn = pg_field_name($rs, $i);
        print $fn . ' ';
        $i++;
    }
    print '<hr>';
}

Converting string to date in PHP

Converting strings to dates in PHP requires the use of two functions. strtotime function converts the string to an epoch timestamp. date function converts the timestamp to the desirable date format.

<?php
$string = "Nov 11, 2011";
$timestamp = strtotime($string);
$date = date("Y-m-d", $timestamp);
print $timestamp . "<br>" . $date;
?>

output

1320987600
2011-11-11

Y prints the date in 4 digit format, m prints the month in two digit format, and d prints the day in two digit format. Alternately, you can use the single line version of the code:

print date("Y-m-d", strtotime("Nov 11, 2011"));

Converting to and from epoch time

Epoch time is Unix timestamp which counts the number of seconds since January 1 1970 00:00:00 UTC. Without getting into long discussion, follow is how your convert between human readable date and epoch time.

Convert Human Readable Date to Epoch Time

<?php
$now = strtotime('2010-04-25');
print $now;    // 1272175200
?>

Convert Epoch Time to Human Readable Time

<?php
$human_date = "";
$human_date=date("Y-m-d", 1251627495);
print $human_date;    // 2009-08-30
print "\n";
$iso8601 = "";
// time() returns current epoch time
$iso8601 = date("c", time());
print $iso8601;     // 2011-01-05T12:22:00-07:00
?>

For more information refer to date and strtotime PHP manuals.

Difference between <?php ?> and <? ?>

<?php ?> is called the safe tag
<? ?> is called the short tag
Depending on the server configuration, you might not be able to use the short tag. It is a good idea to get into the habit of using safe tags because short tags can cause confusion with other tags such as XML:

<?xml version="1.0" ?>

There are rumors that the short tag would be depreciated in PHP 6 but I would believe that when I see it. In the meanwhile, using safe tags is recommended and it not that difficult to type three extra characters.

Encrpypting and Decrypting in PHP

The crypt() function provide one-way encryption. Using one-way encryption is like using a key to lock and unlock something. The key is your password.

To encrypt:
$pass = 'secret';
$encrypted = crypt($pass);
// $encrypted = $1$zaxz8vXb$.lZaoK40w/EtrkkogORYo0

To decrypt:
// entered password
$pass = 'secret';
// $passord is the encrypted password
if (crypt($pass, $encrypted) == $encrypted) {
print 'welcome';
} else {
print 'wrong password';
}

Error: phpsize failed

If you get the following error

ERROR: phpsize failed

This error indicates that you are missing the phpsize application. To fix this problem simply install php5-dev:
Ubuntu

sudo apt-get install php5-dev

Red Hat Family

yum install php5-dev

foreach by value vs foreach by reference

When you use a foreach loop, PHP creates a copy of the current element you are using in your loop. Any changes you make to this element is not saved to the original array. See the first part of the following example:

<?php
$a = array('a','b','c');
foreach ($a as $b) {
  $b = 'z';
}
print_r($a);
foreach ($a as &$b) {
  $b = 'z';
}
print_r($a);
?>

In the second part of the example, we access the array elements by reference using &$b. This allows us to point directly to the variable rather than its copy. Any changes to this variable is a change made to the array element. The output of the program is as follows:

Array
(
  [0] => a
  [1] => b
  [2] => c
)
Array
(
  [0] => z
  [1] => z
  [2] => z
)

How to check whether a file has been included

The is_readable function could be used to check whether a file has been include successfully.

<php
include "file.php";
if (is_readable('file.php')) {
print 'file included successfully';
}
?>

You might wonder what is the point of checking for an included file when the compiler would generate an error a called file is missing or could not be included for some other reason. This sort of check is useful in unit testing and skillful exception handling would allow you to handle this error gracefully.

How to fix problems with European character encoding

Recently, I had to build a multilingual portal. Soon I ran into character encoding problems. Gibberish would appear in place of special characters such as umlaut, accent circonflex, etc. Naturally, I checked out PHP manual, MySQL manual, blogs etc. The solution is easy but the problem needs to be solved at several steps. Basically, you need to make sure that your database and PHP input and output are in utf-8.

1. Set MySQL charset to utf-8
The important part is the charset and collate values on the last line.

create table collection (
  cid int not null primary key, 
  name varchar(255) not null, 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;

2. Set PHP encoding to UTF-8
Add the following line at the top of your PHP code. With this line, you are making sure that utf-8 is used instead of the default latin1 character encoding

mb_internal_encoding("UTF-8");

3. Configure php.ini
If you wish to change the default charset to utf8, open php.ini and set the following:

default_charset = "utf-8"

4. Convert incoming data from MySQL to UTF-8
Incoming data is converted to default encoding of PHP. To make sure you are getting utf-8, add the following two lines of code just after mysql_connect()

mysql_query("SET NAMES 'utf8'");
mysql_query("SET CHARACTER SET 'utf8'");

Installing and uninstalling using PECL

PECL is a repository for PHP Extensions. It provide a directory which contains numerous PHP extensions and hosting facilities where these extensions can be downloaded.

Using PECL to install extensions

$ sudo pecl install xdebug

where xdebug is the extension being installed

Using PECL to uninstall extensions

$ sudo pecl uninstall xdebug

Installing and using phpDocumentor on Ubuntu

phpDocumentor is a tool which creates complete documentation like Javadocs for PHP code.

Installing phpDocumentor

$ sudo apt-get install libapache2-mod-php5

Restart Apache

$ sudo service apache2 restart

Install PEAR. PEAR is a repository of php extensions

$ sudo pear config-set data_dir /var/www

Tell PEAR where to install phpDocumentor

$ sudo pear install --alldeps phpDocumentor

www-data is user Apache on Ubuntu

$ sudo mkdir /var/www/phpDocumentorOuput
$ sudo chown www-data /var/www/phpDocumentorOutput

Using phpDocumentor
You can use phpDocumentor on commandline or via a web interface. For the web interface, type the following http://localhost/phpDocumentor in your browser. Click on Files tab and provide address of the file or directory your intend to create documentation for. Then click on output and specify the output directory. Then hit create button.

On commandline:
Create an output directory and assign proper permissions:

$ sudo mkdir /var/www/docs
$ sudo chown my-user_account /var/www/docs
$ sudo 644 /var/www/docs

Create documentation for one file:

$ phpdoc -d /var/www/my_code_directory/my_code.php -t /var/www/docs

Create documentation all files in a directory and its subdirectories:

$ phpdoc -d /var/www/my_code_directory -t /var/www/docs

Change the look of the documented code

$ phpdoc -o HTML:frames:earthli -d /var/www/my_code_directory -t /var/www/docs

Both javadoc and phpdoc generate documentation for public and protected methods/functions, and variables. All private variables and methods/functions are ignored. To include private variables and functions, add the -pp option as follows:

$ phpdoc -pp -d /var/www/my_code_directory -t /var/www/docs

Installing PHP on Mac OS

Installing PHP is more than just installing the PHP source code on the system. Several libraries are also required to connect to databases, connect to GD, support XML, get LDAP access and so on. All these have to be installed manually on the machine. You can go through the painful process of manual installation and configuration or simply download and install a ready-made package from entropy.ch.

Unless you have very specific needs, you should use this package.

Parsing a sentence in PHP

A sentence can be parsed in many different ways in PHP. A few methods are presented here along with their analysis. Regardless of the language you use for parsing a sentence, you can either match the characters of interest, or match the characters you wish to exclude and split on them or you can use a ready-made function if one is available.

Consider the following code:

$sentence = "Hey, Carol's 18th birthday is 15 days from today.";
$words = preg_split('/\W+/', $sentence);
print_r($words);

Output:

Array
(
    [0] => Hey
    [1] => Carol
    [2] => s
    [3] => 18th
    [4] => birthday
    [5] => is
    [6] => 15
    [7] => days
    [8] => from
    [9] => today
    [10] =>
)

The first example uses \W which matches non-word characters. Non word characters include apostrophe ('), comma (,) and period (.) Carol's is split into two words. Also note the empty cell at the end. Empty cells can be removed with PREG_SPLIT_NO_EMPTY argument as follows:

$sentence = "Hey, Carol's 18th birthday is 15 days from today.";
$words = preg_split('/\W+/', $sentence, -1, PREG_SPLIT_NO_EMPTY);
print_r($words);

Output:

Array
(
    [0] => Hey
    [1] => Carol
    [2] => s
    [3] => 18th
    [4] => birthday
    [5] => is
    [6] => 15
    [7] => days
    [8] => from
    [9] => today
)

In the following example, the first regular expression [^\w']+ matches the word boundary and characters which wish to retain. The second regular expression matches the word and characters we wish to split on.

$sentence = "Hey, Carol's 18th birthday is 15 days from today.";
$words = preg_split("/[^\w']+/", $sentence, -1, PREG_SPLIT_NO_EMPTY);
print_r($words);
$words = preg_split("/[\s.,]+/", $sentence, -1, PREG_SPLIT_NO_EMPTY);
print_r($words);

Output

Array
(
    [0] => Hey
    [1] => Carol's
    [2] => 18th
    [3] => birthday
    [4] => is
    [5] => 15
    [6] => days
    [7] => from
    [8] => today
)
Array
(
    [0] => Hey
    [1] => Carol's
    [2] => 18th
    [3] => birthday
    [4] => is
    [5] => 15
    [6] => days
    [7] => from
    [8] => today
)

In both cases, the regular expression can be customized by adding or removing characters from the square brackets [].

In the following example, the PHP str_word_count() function is used.

$sentence = "Hey, Carol's 18th birthday is 15 days from today.";
$words = str_word_count($sentence, 1, '0123456789');
print_r($words);

Output

Array
(
    [0] => Hey
    [1] => Carol's
    [2] => 18th
    [3] => birthday
    [4] => is
    [5] => 15
    [6] => days
    [7] => from
    [8] => today
)

This code matches word characters and additional allowed symbols 0123456789. Not that an apostrophe (') is considered a word character.

Personally, I prefer the last method over regular expressions because it is simple, well documented, widely commented, well-tested, and being a built-in function, it probably considers all kinds of issue which didn't cross my mind while writing regular expressions.

permission denied when including a subdirectory

Suppose your project is installed at /var/www/myproject and this project includes or requires files in /var/www/myproject/modules, you simply need to use include_once('modules/mfile.php'); to access a in the modules directory.

If you get at message like the following:

[error] [client ::1] PHP Warning: require_once(modules/AccessDenied.php): failed to open stream: Permission denied in /var/www/myproject/index.php on line 2
[error] [client ::1] PHP Fatal error: require_once(): Failed opening required 'modules/mfile.php' (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/myproject/index.php on line 2

It simply indicates that it does not have access to this file either because apache does not have sufficient permissions on this file or it does not have sufficient permissions to the subdirectory. To fix this problem, simply do the following:

$ chmod 755 modules
$ chmod 755 modules/mfile.php

This seems like a commonsense thing but the first reaction to this error message is to check php.ini, apache settings, and more path settings.

PHP Benchmark Results

Benchmarking is the process of evaluating existing processes and identifying best practices. For example, there are three ways to loop through an array, we would test each method and identify the best performing method. In terms of code, this very often means identifying methods that would be least expensive in terms of CPU time and memory consumption.

Following is a simple benchmark script. It compares while loop with for loop.

$s = microtime(true);
$i=0;
while ($i < 1000000) { 
  $sm += $i;
  $i++;
}
$e = microtime(true);
$t = $e - $s;
print "while loop: $t seconds\n";

$s = microtime(true);
for ($i = 0; $i < 1000000; $i++) { 
  $sm += $i;
}
$e = microtime(true);
$t = $e - $s;
print "for loop: $t seconds\n";

If you run this code several times, you would see that there is not much difference between the two. This is not surprising as for loop is simply a different syntax of the while loop.

There are usually several ways to code the same task in most languages. Following ia a brief benchmarking summary.

Looping through hash value

// reading values
1. while(list(,$v) = each($h)) {}	100%
2. foreach($h as $v) {}			200%

// reading key,value pairs
1. foreach($h as $k=>$v) {}		100%
2. while(list($k,$v)=each($h)){}	115%

// modifying values
1. while(list(,$v) = each($h)) { $h[$k] = "x"; }	100%
2. foreach($h as $k=>$v) { $h[$k] = "x"}		200%

Note the the 100% in different sections do not correlate. The foreach method would take twice the time the while loop method would take.

To delete many elements from an array, don't use array_splice(). Instead clone array elements you wish to keep.

$newarray[] = clone sarray[elements-to-keep]
$array = $newarray;

If you are interested in viewing memory usage, use memory_get_usage() function:

// your code
echo convert(memory_get_usage(true)); // 123 kb
// your code

function convert($size) {
  $unit=array('b','kb','mb','gb','tb','pb');
  return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}

This code was submitted by xelozz at php.net.

Using PEAR Benchmark for benchmarking
To use PEAR benchmark, you need to first install PEAR on your system. Then run the following command to install PEAR benchmark:

pear install benchmark

Once PEAR benchmark in installed, run the following code:

include_once("Benchmark/Timer.php");
$b = new Benchmark_Timer;
$b->start();
$b->setMarker('marker');

// your  code goes here
for ($=0; $i <1000000; $i++) {
  // 1 million do nothings
}
$b->stop();

// benchmarking information
print_r($b->getProfiling());

PHP date arithmetic

strtotime() function can be used for date arithmetic. Following are some examples:

Get next date

print date('Y-m-d', strtotime('+1 day', strtotime('2013-09-30')));


Prints 2013-10-01

Get previous month

print date('Y-m-d', strtotime('-1 month', strtotime('2013-09-30')));


Prints 2013-08-30

Go back 5 years

print date('Y-m-d', strtotime('-5 year', strtotime('2013-09-30')));


Prints 2013-04-30

PHP Error Logs

PHP errors are by default set to go to the apache error log. On Ubuntu, the error log is located at /var/log/apache2/error.log. If you are a PHP developer, it is good idea to open a small terminal window and type the following:

tail -f /var/log/apache2/error.log

This would essentially give you a live view of the error log. As you generate errors, you would see the error messages on the terminal.

Displaying errors in browser
To display errors in your browser, open php.ini file for editing. Find "display_errors" and set it to "on".

PHP fatal error - call to undefined function mb_string

Author: Mushtaq Ahmad

This error tells us that the mb_string library is not installed. mb_String mb_String is a library, which provides support for UTF-8 and UCS-2 characters. PHP uses ASCII by default which is a 256 character coding system. This means that it uses 8 bits to encode English alphabet and commonly used symbols such as ,.?;:"+-$#@ and many more. However, it does not code for foreign language characters such as é, ç, â, è, ñ, ü, and many others. mb_string provides double byte, i.e. 2 x 8bits to code for a character. This permits code for 65536 characters.

To remove this error, simply install the library, and add its extension to php.ini file.

Installing mb_string on Ubuntu

$ sudo apt-get install php-mbstring

This command install the library and configures the php.ini file.

Installing mb_string on Red Hat family

$ sudo yum install php-mbstring

This command install the library and configures the php.ini file.

Installing mb_string on Microsoft Windows
As always, all non-click tasks are complicated in Microsoft systems. For information on installing and configuring mb_string on Microsoft Windows, visit http://php.net/manual/en/install.windows.extensions.php.

PHP require() vs. include()

PHP provides four functions which enable you to insert code from other files. All four can take a local file or URL as input. None of them can import a remote file. require() and include() functions are virtually similar in their function except for the way they handle an irretrievable resource. include() and include_once() provide a warning if the resource cannot be retrieved and try to continue execution of the program if possible. require() and require_once functions provide stop processing the page if they cannot retrieve the resource.

Why include_once() and require_once()
The include_once() and require_once() functions are handy in situations where multiple files may reference the same included code. For example:

File A.php includes File B.php and C.php
File B.php includes File C.php
File C.php has been included twice, so the interpreter would print an error. Since a function cannot be redefined once it’s declared, this restriction can help prevent errors.

If both File A.php and File B.php use include_once() or require_once() to import File C.php, no errors would be generated. PHP would understand that you only want one instance of the code in File C and would not try to redeclare the functions.

It is best to use require_once() to include files which contain necessary code and include_once() to include files that contain content which the program can run without e.g. HTML, CSS, etc.

PHP usort explained

The usort function sorts an array by values where the values are sorted by a user-defined function. usort has the following syntax

bool usort ( array &$array , callback $cmp_function )

The comparison function takes two arguments and it must return integer values, either 0, positive integer, or negative integer.

- negative integer = first argument is smaller than the second
- zero = both arguments are equal
- positive integer = first argument is greater than the second

usort assigns new key for each element in the array. To preserve keys, use another sort function. The bool returns TRUE or FALSE to indicate whether the function succeeded or failed.

A simple example:

function cmp($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

$a = array(3, 2, 5, 6, 1);
print_r($a);
usort($a, "cmp");
print_r($a);

If your comparison function is inside a class you would need to call it as follows:

usort($a, array($this,"cmp"));

Otherwise you would get an Invalid Comparison Function error.

PHP Warning: strtotime(): It is not safe to rely on the system's timezone settings.

If a default timezone is not set in your php.ini, then you get the following warning:

"Warning: strtotime(): It is not safe to rely on the system's timezone settings. Please use the date.timezone setting, the TZ environment variable or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'CDT/-6.0/DST'"

To get rid of this warning, open you php.ini file and set a value for date.timezone

date.timezone = 'America/Edmonton'

The following list would help you in choosing your timezone

date.timezone = "America/Toronto"
date.timezone = "America/Chicago"
date.timezone = "Asia/Baghdad"
date.timezone = "Asia/Baku"
date.timezone = "Asia/Shanghai"
date.timezone = "Asia/Islamabad"
date.timezone = "Australia/Sydney"
date.timezone = "Australia/Canberra"
date.timezone = "Europe/London"
date.timezone = "Europe/Berlin"
date.timezone = "Europe/Paris"
date.timezone = "Europe/Madrid"

print_r into a variable

print_r() prints array contents in a user-friendly format. The output of print_r() can also be stored into a variable. Just remember to pass your array into print_r() with a true flag as follows:

$a = array('pass','print_r','into','variable');
$variable = print_r($a,true);
print $variable;

output

Array
(
    [0] => pass
    [1] => print_r
    [2] => into
    [3] => variable
)

Printing print_r on one line

$a = array('pass','print_r','into','variable');
$variable = print_r($a,true);
$str = str_replace("\n", "", $variable);
$str = str_replace(" ", "", $str);
print $str;

or the line noise version

$a = array('pass','print_r','into','variable');
print str_replace(" ", "", str_replace("\n", "", print_r($a,true)));

output

Array([0]=>pass[1]=>print_r[2]=>into[3]=>variable)

proc_open tutorial and examples

A great advantage of Unix-based systems is the wealth of powerful command line tools. Very often it is quite useful to use tools such as sed, grep, or programs written in other programming languages instead of recoding in PHP. PHP has a very powerful function that allow you to execute external programs from your PHP script; proc_open(). proc_open() is very powerful but also difficult to understand.

proc_open() is used open a process which it returns as a resource (running process in our case). It takes the following parameters as input:

  1. command as string: This is what you type in the command line, e.g. ls -al
  2. array of descriptors
  3. array of pipes
  4. working directory
  5. environment variables

proc_open() STDIN, STDOUT, STDERR

$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","./error.log","a")
) ;

The child process would read from the pipe define in the second line and write to the pipe defined in the third line. All errors would be written to the error log file defined in the third line.

Calling shell from PHP

In this example, we call '/bin/sh' and run the 'cal -3' command.

$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","./error.log","a")
) ;

// define current working directory where files would be stored
$cwd = './' ;
// open process /bin/sh
$process = proc_open('/bin/sh', $descriptorspec, $pipes, $cwd) ;

if (is_resource($process)) {

  // anatomy of $pipes: 0 => stdin, 1 => stdout, 2 => error log
  fwrite($pipes[0], 'cal -3') ;
  fclose($pipes[0]) ;

  // print pipe output
  echo stream_get_contents($pipes[1]) ;

  // close pipe
  fclose($pipes[1]) ;
 
  // all pipes must be closed before calling proc_close. 
  // proc_close() to avoid deadlock
  proc_close($process) ;
}

In this program, we call /bin/sh. We then pipe the command 'cal -3' to it. Finally, we print the output of process. It is important to close the pipes in before close the process with proc_close(). proc_close() must be called to avoid deadlocks and also for security reasons.

The program should print you the calendar for 3 months.

Executing Perl code from PHP

proc_open can execute processes regardless of the language the the tool was coded in. Here I would execute a simple Perl program as an example.

reprint.pl
This Perl program simply reprints the command argument.

#!/usr/bin/perl
print @ARGV;

proc_open_perl_test.php
This PHP programs opens a process to execute a Perl program, passes it an argument and then prints the piped output of the Perl program.

$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","./error.log","a")
) ;

// define current working directory where files would be stored
$cwd = './' ;

// open process reprint.pl and pass it an argument
$process = proc_open('./reprint.pl ' . $argv[1], $descriptorspec, $pipes, $cwd) ;

if (is_resource($process)) {

  // print pipe output
  echo stream_get_contents($pipes[1]) ;

  // close pipe
  fclose($pipes[1]) ;
 
  // close process
  proc_close($process) ;
}

To run this program, type:

php proc_open_perl_test.php argument

The program should return the argument you typed.

Debugging

The code would generate errors, if you do not give write permissions to your working directory.
The external files you call must also have sufficient right for you script to be able to read or execute them.

Push and Pop

array_push() and array_pop() functions are used to push and pop elements on a array. These functions have the following syntax:

array_push($array,$element);
$element = array_pop($array);

Lets look at the following code:

$mya = array(0 => "zero",1 => "one",2 => "two");
array_push($mya, "three");
$mya[] = "four";
print_r($mya);

This program would produce the following results. array_push() adds an element at the end of the array. The code on the last line is equivalent to a pop.

Array
(
[0] => zero
[1] => one
[2] => two
[3] => three
[4] => four
)

array_pop removes the last element from an array. Let's look at the following program:

$mya = array(0 => "zero",1 => "one",2 => "two");
$n = array_pop($mya);
print "$n\n";
print_r($mya);

This program produces the following result.

two
Array
(
[0] => zero
[1] => one
)

Reading commandline input in PHP

In PHP, all commandline parameter are passed to the $argv array. Following example shows how to use this array:

<?php
    $op1 = $argv[1];
    $op2 = $argv[2];
    $sum = $op1 + $op2;
    print 'Sum: ' . $sum . "\n";
    print_r($argv);
?>

$argv[1] and $argv[2] contain the passed parameters in the order they were typed. The last line prints a dump of the data where the first parameter is the name of the file.

$ php sum.php 2 3
Sum: 5
Array
(
    [0] => sum.php
    [1] => 2
    [2] => 3
)

Another way to read command line parameters is to use STDIN.

<?php
// request  input
fwrite(STDOUT, "Enter password: ");

// get input
$pass = trim(fgets(STDIN));

// write response
if ($pass === 'pass') {
    fwrite(STDOUT, "Welcome!");
} else {
    fwrite(STDOUT, "Wrong password");
}
print "\n";
?>

STDIN reads input from commandline and STDOUT writes something to the screen.

$ php pass.php 
Enter password: pass
Welcome!

Sorting objects by their properties

Sorting objects by their properties might seem complicated but it is quite simple in PHP. To demonstrate, I created class Node and a class NodeBox which creates the Nodes and stores them in an array. NodeBox is also capable of sorting its nodes.

Lets begin by looking at the Node class:

Class Node {
  private $nMass;

  public function Node($mass)
  {
    $this->nMass = $mass;	
  }

  public function getNodeMass()
  {
    return $this->nMass;
  }
}


Each node has a private data member $nMass. I can be access by getNodeMass() function. Now the NodeBox class.

Class NodeBox
{
  public $aNodes; // array of nodes

  public function NodeBox()
  {
    $this->aNodes = array();
  }

  public function createNodes() 
  {
    for($i = 0; $i < 5; $i++) {
      $this->aNodes[] = new Node(rand()%9);
    }
  }

  public function sortNodes() 
  {
    usort($this->aNodes, array($this,"cmp_nodemass"));
  }

  private function cmp_nodemass($x, $y)
  {
    // convert strings to floats and compare
    $a = intval($x->getNodeMass()); 
    $b = intval($y->getNodeMass());
    if ($a == $b) { return 0; }
    return ($a < $b) ? -1 : 1;
  }
}


createNodes() creates nodes with mass (0-9) using a random function. sortNodes() simply passes the right parameters to usort() the right parameters. The array of objects and the comparison function. cmp_nodemass() is the comparison function. $x and $y are Node objects in the array.
intval($x->getNodeMass())

$x is a Node object. getNodeMass() is a public function of Node. $x->getNodeMass() calls this function. It returns a the mass of the Node object as a string. We need to convert it to integer before making the comparison. Thus the intval() function.

cmp_nodemass() sorts in ascending order. To change to descending order, simply change $a < $b in the last line to $a > $b.

Time to call our classes:


$o = new NodeBox;
$o->createNodes();
print_r($o->aNodes);
print '<br>\n=============================================\n<br>';
$o->sortNodes();
print_r($o->aNodes);

Once you run the code on a browser, view page source to get a more readable view. The results should be something like:

Array
(
    [0] => Node Object
        (
            [nMass:private] => 4
        )

    [1] => Node Object
        (
            [nMass:private] => 3
        )

    [2] => Node Object
        (
            [nMass:private] => 3
        )

    [3] => Node Object
        (
            [nMass:private] => 2
        )

    [4] => Node Object
        (
            [nMass:private] => 3
        )

)

Array ( [0] => Node Object ( [nMass:private] => 2 ) [1] => Node Object ( [nMass:private] => 3 ) [2] => Node Object ( [nMass:private] => 3 ) [3] => Node Object ( [nMass:private] => 3 ) [4] => Node Object ( [nMass:private] => 4 ) )

Type casting in PHP

PHP does not support explicit type definition in variable declaration. For example, you CANNOT declare a variable as follows:

int $count = 10;

In PHP, a variable's type is determined by the context in which the variable is used.

$student = "23";    // $students is a string
$girls = 13;         // $girls is an int
$boys = $students - $girls;    // all three variables are converted to int.

There are many scenarios when automatic typecasting could lead to erroneous functionality. In such cases, you can manually cast the variables.

$count = 1;     // $count is an int but I need it to be an boolean
$count = (bool) $count;    // $count is a boolean now

Following casts are allowed in PHP:

binary will cast to binary
bool, boolean will cast to boolean
float, double will cast to float
int, integer will cast to integer
string will cast to string
array and object can also be used for casting

Validating Email in PHP

Validating email is more difficult than one might think. Recently I found this this code at PHP.net and I feel a need to republish this to emphasize its effectiveness and simplicity.

$email = "user@email.com";
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    echo "E-mail is not valid";
} else {
    echo "E-mail is valid";
}

Where is php.ini

I recently received an email which where the person was asking me how to locate php.ini. My online response was:

$ locate php.ini

He replied that this returns several php.ini files. Which one is being loaded in my webroot? The most definitive way to answer this question is to create a file called phpinfo.php inside the webroot with the following code

<?
  phpinfo();
?>

Then open this file in your browser. phpinfo() prints your php settings in a nice tabular format. Scroll down the page and locate "Loaded Configuration File". The address of the php.ini file which is being loaded will be listed here.

xmlEscapeEntities : char out of range

If you are generating XML from UTF-8 data source such a database table encoded in UTF-8, you will "XMLEscapeEntities: char out of range" error unless you encode the XML in UTF-8 as well. Just edit your new DOMDocument statement to the following to fix this problem.

$xml = new DOMDocument('1.0','utf-8');
next day delivery viagra