ZEND Certified PHP 5 Engineer – Thats Me !


Why The ZEND PHP Certification ?


  1. I like learning. Nothing like an exam to make one explore the depth of a subject.
  2. A certification helps in asserting a neutral organization’s opinion about how good your knowledge is. If I had to test my knowledge in a certification exam , it had to be PHP since I have been working with it for quite some time.
  3. I thought the ZCE Logo would look good on my papers :P

Study Material


  • PHP Architects ZEND PHP 5 Study guide PDF.
  • PHP Architects Zend PHP Certification Practice Test Book PDF (its for PHP 4 but contains some very good questions).

Preparation


  • I prepared my own short notes from the Study Guide which contained the important stuff from each chapter.
  • The Study Guide mentions lots of stuff……but I never took any line by its face value. I tested each functionality myself as I read it. Since the books contains quite a few mistakes, its best to try it out yourself.

Exam Experience


  • Its not permitted to reveal the questions of the exam so I shall only comment in general on it.
  • The exam wasn’t easy. Why? Imagine this – You learn how the concept A works. then you learn about concept B. The exam has questions that require the output if both concepts A & B are used together !
  • I was done with the exam in an hour. I went through the questions (the doubtful ones) which I had marked for review for the remaining 30 min.
  • I was ready for another week of studying & another attempt at this exam when I was pleasantly surprised by the ‘Congratulations’ message :-)

Lessons Learn’t


  • You can be aware of a number of such complex scenarios of PHP if you encountered them while working on some project involving PHP. I was…& it helped a lot.
  • Its apparent that a curious person must have had a hand in creating the database of questions since only such a person would think of the consequences of mixing different concepts with each other. I am curious by nature…& my frequent trials of concepts helped me.
  • I only wish I had gone through the string, array & stream functions listed in php.net site. That would have reduced the tense moments I had during the exam. I was so enamoured by XML, that I spent a lot of time on it. It didn’t help me in the exam but it did make me a big fan of XML :D .
  • All in all , It was a good exam. I was a little unsure of about 50% of the questions. My reaction to some questions was : ‘Oh..thats a different way to look at things :!: ‘ .After the exam, I cleared those doubts using my trusty comp.
  • It was nice to learn something new. That is how an exam should be. It should challenge your boundaries of knowledge & also encourage you to learn more. Thank You ZEND. We shall probably meet again after PHP 6 :)

Update :
Though the site gives you a time frame of 8 weeks, the ZEND Certificate (hard copy) reached me in only 2 weeks !


PHP : XML Create-Add-Edit-Modify using DOM , SimpleXML , XPath

Over the last few working days, I spent a quite a bit of time playing around with XML. While searching through the net, I found few comprehensive PHP XML guides. There never was a ’1 stop all operations’ guide for learning XML.
As such I decided to club together examples of all kinds of operations I ever did on XML in a single post. I hope it benefits others out there who wish to learn more about XML manipulation.
Note : Since the post got quite large, I decided to only use the Tree Map style parsers – DOM & Simple XML.

XML Pic

Operations Performed:
(1) Create XML OR Array to XML Conversion OR CDATA Element Eg
(2) Edit XML – Edit/Modify Element Data (accessed serially)
(3) Edit XML – Edit specific Elements (accessed conditionally)
(4) Edit XML – Element Addition (to queue end)
(5) Edit XML – Element Addition (to queue start)
(6) Edit XML – Element Addition (before a specific node)
(7) Delete Elements (accessed serially)
(8) Delete Elements (accessed conditionally)
(9) Rearrange / Reorder Elements
(10) Display Required data in XML Form itself OR Remove all children nodes save one OR Copy/Clone Node Eg OR Compare/Search non numeric data (like date or time) to get result.

library.xml will be used in all operations.
ps : I have added the indention & spaces outside the tags in the below xml for a presentable xml form.
Remove them before saving your xml file else most of the usual XML functions wont work in the desired manner.

<?xml version="1.0"?>
<library>
    <book isbn="1001" pubdate="1943-01-01">
        <title><![CDATA[The Fountainhead]]></title>
        <author>Ayn Rand</author>
        <price>300</price>
    </book>
    <book isbn="1002" pubdate="1954-01-01">
        <title><![CDATA[The Lord of the Rings]]></title>
        <author>J.R.R.Tolkein</author>
        <price>500</price>
    </book>
    <book isbn="1003" pubdate="1982-01-01">
        <title><![CDATA[The Dark Tower]]></title>
        <author>Stephen King</author>
        <price>200</price>
    </book>
</library>

#######################################
// (1) Create XML OR
Array to XML Conversion OR
CDATA Element Eg
#######################################

// (i) SimpleXML :

// Cant create CDATA element for title in SimpleXML.
function fnSimpleXMLCreate()
    {
        $arr = array(array('isbn'=>'1001', 'pubdate'=>'1943-01-01', 'title'=>'The Fountainhead',
                               'author'=>'Ayn Rand', 'price'=>'300'),
                         array('isbn'=>'1002', 'pubdate'=>'1954-01-01',
                               'title'=>'The Lord of the Rings', 'author'=>'J.R.R.Tolkein',
                               'price'=>'500'),
                         array('isbn'=>'1003', 'pubdate'=>'1982-01-01', 'title'=>'The Dark Tower',
                               'author'=>'Stephen King', 'price'=>'200'));
        
        $library = new SimpleXMLElement('<library />');
        
        for($i=0;$i<3;$i++)
        {
            $book = $library->addChild('book');
            $book->addAttribute('isbn', $arr[$i]['isbn']);
            $book->addAttribute('pubdate', $arr[$i]['pubdate']);
            $book->addChild('title', $arr[$i]['title']); //cant create CDATA in SimpleXML.
            $book->addChild('author', $arr[$i]['author']);
            $book->addChild('price', $arr[$i]['price']);
        }
       
        $library->asXML('library.xml');
    }


// (ii) DOM :

function fnDomCreate()
    {
       $arr = array(array('isbn'=>'1001', 'pubdate'=>'1943-01-01', 'title'=>'The Fountainhead',
                               'author'=>'Ayn Rand', 'price'=>'300'),
                         array('isbn'=>'1002', 'pubdate'=>'1954-01-01',
                               'title'=>'The Lord of the Rings', 'author'=>'J.R.R.Tolkein',
                               'price'=>'500'),
                         array('isbn'=>'1003', 'pubdate'=>'1982-01-01', 'title'=>'The Dark Tower',
                               'author'=>'Stephen King', 'price'=>'200'));
        
        $dom = new DOMDocument();
        $library = $dom->createElement('library');
        $dom->appendChild($library);
        
        for($i=0;$i<3;$i++)
        {
            $book = $dom->createElement('book');
            $book->setAttribute('isbn',$arr[$i]['isbn']);
             $book->setAttribute('pubdate',$arr[$i]['pubdate']);
            
            //$prop = $dom->createElement('title', $arr[$i]['title']);
            $prop = $dom->createElement('title');
            $text = $dom->createCDATASection($arr[$i]['title']);
            $prop->appendChild($text);
            $book->appendChild($prop);
            
            $prop = $dom->createElement('author', $arr[$i]['author']);
            $book->appendChild($prop);
            $prop = $dom->createElement('price', $arr[$i]['price']);
            $book->appendChild($prop);
            $library->appendChild($book);
        }
        //header("Content-type: text/xml");
        $dom->save('library.xml');
    }

#######################################
// (2) Edit XML – Edit/Modify Element Data (accessed serially)
#######################################

// (i) SimpleXML :

// Edit Last Book Title
function fnSimpleXMLEditElementSeq()
    {
        $library = new SimpleXMLElement('library.xml',null,true);
        $num = count($library);
        $library->book[$num-1]->title .= ' - The Gunslinger';
        header("Content-type: text/xml");
        echo $library->asXML();
    }


// (ii) DOM :

//Edit Last Book Title
    function fnDOMEditElementSeq()
    {
        $dom = new DOMDocument();
        $dom->load('library.xml');
        $library = $dom->documentElement;
        $cnt = $library->childNodes->length;
        
        $library->childNodes->item($cnt-1)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series'; 
       // 2nd way #$library->getElementsByTagName('book')->item($cnt-1)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
       
       //3rd Way
       //$library->childNodes->item($cnt-1)->childNodes->item(0)->nodeValue .= ' Series';
        header("Content-type: text/xml");
        echo $dom->saveXML();
    }

#######################################
// (3) Edit XML – Edit specific Elements (accessed conditionally)
#######################################

// (i) SimpleXML :

//Edit Title of book with author J.R.R.Tolkein
    function fnSimpleXMLEditElementCond()
    {
        $library = new SimpleXMLElement('library.xml',null,true);
        $book = $library->xpath('/library/book[author="J.R.R.Tolkein"]');
        $book[0]->title .= ' Series';
        header("Content-type: text/xml");
        echo $library->asXML();
    }


// (ii) DOM (with XPath):

 //Edit Title of book with author J.R.R.Tolkein
    function fnDOMEditElementCond()
    {
        $dom = new DOMDocument();
        $dom->load('library.xml');
        $library = $dom->documentElement;
        $xpath = new DOMXPath($dom);
        $result = $xpath->query('/library/book[author="J.R.R.Tolkein"]/title');
        $result->item(0)->nodeValue .= ' Series';
        // This will remove the CDATA property of the element.
        //To retain it, delete this element (see delete eg) & recreate it with CDATA (see create xml eg).
        
        //2nd Way
        //$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
       // $result->item(0)->getElementsByTagName('title')->item(0)->nodeValue .= ' Series';
        header("Content-type: text/xml");
        echo $dom->saveXML();
        
    }

#######################################
// (4) Edit XML – Element Addition (to queue end)
#######################################

// (i) SimpleXML :

//Add another Book to the end
    function fnSimpleXMLAddElement2End()
    {
        $library = new SimpleXMLElement('library.xml',null,true);
        $book = $library->addChild('book');
        $book->addAttribute('isbn', '1004');
        $book->addAttribute('pubdate', '1960-07-11');
        $book->addChild('title', "To Kill a Mockingbird");
        $book->addChild('author', "Harper Lee");
        $book->addChild('price', "100");
        header("Content-type: text/xml");
        echo $library->asXML();
    }


// (ii) DOM :

    //Add another Book to the end
    function fnDOMAddElement2End()
    {
        $dom = new DOMDocument();
        $dom->load('library.xml');
        $library = $dom->documentElement;
        
        $book = $dom->createElement('book');
        $book->setAttribute('isbn','1000');
        $book->setAttribute('pubdate','1960-07-11');
        
        $prop = $dom->createElement('title');
        $text = $dom->createTextNode('To Kill a Mockingbird');
        $prop->appendChild($text);
        $book->appendChild($prop);
        
         $prop = $dom->createElement('author','Harper Lee');
        $book->appendChild($prop);
        $prop = $dom->createElement('price','100');
        $book->appendChild($prop);
        
        $library->appendChild($book);
        header("Content-type: text/xml");
        echo $dom->saveXML();
    }

#######################################
//(5) Edit XML – Element Addition (to queue start)
#######################################

// (i) SimpleXML :

// Add a Book to List Start
// Insert Before Functionality not present in SimpleXML 
// We can integrate DOM with SimpleXML to do it.
    function fnSimpleXMLAddElement2Start()
    {
        $libSimple = new SimpleXMLElement('library.xml',null,true);
        $libDom = dom_import_simplexml($libSimple);
        
        $dom = new DOMDocument();
        //returns a copy of the node to import
        $libDom = $dom->importNode($libDom, true);
        //associate it with the current document.
        $dom->appendChild($libDom);
        
        fnDOMAddElement2Start($dom); //see below DOM function
    }


// (ii) DOM :

function fnDOMAddElement2Start($dom='')
    {
        if(!$dom)
        {
            $dom = new DOMDocument();
            $dom->load('library.xml');
        }
        $library = $dom->documentElement;
        #var_dump($library->childNodes->item(0)->parentNode->nodeName);
        $book = $dom->createElement('book');
        $book->setAttribute('isbn','1000');
        $book->setAttribute('pubdate','1960-07-11');
         
        $prop = $dom->createElement('title','To Kill a Mockingbird');
        $book->appendChild($prop);
         $prop = $dom->createElement('author','Harper Lee');
        $book->appendChild($prop);
         $prop = $dom->createElement('price','100');
        $book->appendChild($prop);
        
        $library->childNodes->item(0)->parentNode->insertBefore($book,$library->childNodes->item(0));
        header("Content-type: text/xml");
        echo $dom->saveXML();
    }

#######################################
// (6) Edit XML – Element Addition (before a specific node)
#######################################

// (i) SimpleXML :

// Add a Book Before attribute isbn 1002
    // Insert Before Functionality not present in SimpleXML 
    // We can integrate DOM with SimpleXML to do it.
    function fnSimpleXMLAddElementCond()
    {
        $libSimple = new SimpleXMLElement('library.xml',null,true);
        $libDom = dom_import_simplexml($libSimple);
        
        $dom = new DOMDocument();
        //returns a copy of the node to import
        $libDom = $dom->importNode($libDom, true);
        //associate it with the current document.
        $dom->appendChild($libDom);
        
        fnDOMAddElementCond($dom); //see below DOM eg.
    }


// (ii) DOM :

// Add a Book Before isbn 1002
    function fnDOMAddElementCond($dom='')
    {
        if(!$dom)
        {
            $dom = new DOMDocument();
            $dom->load('library.xml');
        }
        $library = $dom->documentElement;
        
        $book = $dom->createElement('book');
        $book->setAttribute('isbn','1000');
        $book->setAttribute('pubdate', '1960-07-11');
        
        $prop = $dom->createElement('title','To Kill a Mockingbird');
        $book->appendChild($prop);
         $prop = $dom->createElement('author','Harper Lee');
        $book->appendChild($prop);
        $prop = $dom->createElement('price','100');
        $book->appendChild($prop);
        
        $xpath = new DOMXPath($dom);
        $result = $xpath->query('/library/book[@isbn="1002"]');
        $library->childNodes->item(0)->parentNode->insertBefore($book,$result->item(0));
        header("Content-type: text/xml");
        echo $dom->saveXML();
    }

#######################################
// (7) Delete Elements (accessed serially)
#######################################

// (i) SimpleXML :

// Delete 2nd book
    function fnSimpleXMLDeleteSeq()
    {
        $library = new SimpleXMLElement('library.xml',null,true);
        //$library->book[1] = null; // this only empties content
        unset($library->book[1]);
        header("Content-type: text/xml");
        echo $library->asXML();
        
    }


// (ii) DOM :

// Delete 2nd Book
    function fnDOMDeleteSeq()
    {
        $dom = new DOMDocument();
        $dom->load('library.xml');
        $library = $dom->documentElement;
        
        $library->childNodes->item(0)->parentNode->removeChild($library->childNodes->item(1));
        
        header("Content-type: text/xml");
        echo $dom->saveXML();
    }

#######################################
// (8) Delete Elements (accessed conditionally)
#######################################

// (i) SimpleXML :

// Delete a book with  200<price<500
    // Not possible to delete node found via XPath in SimpleXML. See below.
    function fnSimpleXMLDeleteCond()
    {
        $library = new SimpleXMLElement('library.xml',null,true);
        $book = $library->xpath('/library/book[price>"200" and price<"500"]');
        
        //Problem here....not able to delete parent node using unset($book[0]);
        // unset of parent node only works when accessing serially. eg : unset($library->book[0]);
        
        //header("Content-type: text/xml");
        //echo $library->asXML();
        
    }


// (ii) DOM :

// Delete the book with  200<price<500 
    function fnDOMDeleteCond()
    {
        $dom = new DOMDocument();
        $dom->load('library.xml');
        $library = $dom->documentElement;
        $xpath = new DOMXPath($dom);
        $result = $xpath->query('/library/book[price>"200" and price<"500"]');
        $result->item(0)->parentNode->removeChild($result->item(0));
        header("Content-type: text/xml");
        echo $dom->saveXML();
    }

#######################################
// (9) Rearrange / Reorder Elements
#######################################

// (i) SimpleXML :

// Exchange Position of 2nd book with 3rd : fnSimpleXMLRearrange(2,3);
// Due to absence of an inbuilt function (DOM has it), we have to make our own function in SimpleXML.
//Better to use DOM.
function fnSimpleXMLRearrange($num1,$num2)
{
     $libSimple= new SimpleXMLElement('library.xml',null,true);
     //$library->book[3] = $library->book[0]; // this doesnt work
 
    $libDom = dom_import_simplexml($libSimple);

    $dom = new DOMDocument();
    //returns a copy of the node to import
    $libDom = $dom->importNode($libDom, true);
    //associate it with the current document.
    $dom->appendChild($libDom);

    fnDOMRearrange($num1,$num2,$dom); // see below DOM function
}


// (ii) DOM :

// Exchange Position of 2nd book with 3rd : fnDOMRearrange(2,3);
function fnDOMRearrange($num1,$num2,$dom=0)
{
    if(!$dom)
    {
        $dom = new DOMDocument();
        $dom->load('library.xml');
    }
    $dom = new DOMDocument();
    $dom->load('library.xml');
    $library = $dom->documentElement;
	$cnt = $library->childNodes->length;
	//echo '<br> count : ' . $cnt;

    if ($num1 > $num2) { // ensure $num1 always is less than $num2
        $num3 = $num1;
        $num1 = $num2;
        $num2 = $num3;						
    }
     
    $index1 = fnDOMConvIndex($num1,  $cnt);
    $index2 = fnDOMConvIndex($num2,  $cnt);
    /*for ($iter = 0; $iter <= $cnt; $iter++) {
        echo '<hr>' . $iter . '<br>' .  $library->childNodes->item($iter)->nodeValue;
    }*/
            
    $library->childNodes->item(0)->parentNode->insertBefore($library->childNodes->item($index1), $library->childNodes->item($index2)); // put x before y
    $library->childNodes->item(0)->parentNode->insertBefore($library->childNodes->item($index2), $library->childNodes->item($index1)); // put y before x 

    header("Content-type: text/xml");
    echo $dom->saveXML();
}
function fnDOMConvIndex($num,  $cnt)
{
    // echo '<br>' . $num;
    if ($num != 1) {
        $maxIndex = floor($cnt/2);
        //echo '<br>max: ' . $maxIndex;
        if ($maxIndex == $num) {
            $num = $cnt-2;
        } else {
            $num = ($num%2)?($num+2):($num+1); //Always odd index due to nature of DOM Element Index.
        }
    }         
    
    // echo '<br>' . $num;
    return $num;
}

#######################################
// (10) Display Required data in XML Form itself OR
Remove all children nodes save one OR
Copy/Clone Node Eg OR
Compare/Search non numeric data (like date or time) to get result.
#######################################

// (i) SimpleXML :

// Display Books published after 1980 in XML Form itself.
// No function to copy node directly in SimpleXML.
// Its simpler for this functionality to be implemented in DOM.
    function fnSimpleXMLDisplayElementCond()
    {
        $library = new SimpleXMLElement('library.xml',null,true);
        $book = $library->xpath('/library/book[translate(@pubdate,"-","")>translate("1980-01-01","-","")]');
        // Manually create a new structure then add searched data to it (see create xml eg.)
    }


// (ii) DOM :

// Display Books published after 1980 in XML Form itself.
    function fnDOMDisplayElementCond()
    {
        $dom = new DOMDocument();
        $dom->load('library.xml');
        $library = $dom->documentElement;
        $xpath = new DOMXPath($dom);
        
        // Comparing non numeric standard data
        $result = $xpath->query('/library/book[translate(@pubdate,"-","")>translate("1980-01-01","-","")]');
        // For simpler search paramater use this :
        //$result = $xpath->query('/library/book[author="J.R.R.Tolkein"]');
        
        // Copy only node & its attributes not its contents.
        $library = $library->cloneNode(false);
        // Add the 1 element which is search result.
        $library->appendChild($result->item(0));
        
        header("Content-type: text/xml");
        echo $dom->saveXML($library);
    }

Lessons Learn’t :

  • SimpleXML is fantastic for those who will only briefly flirt with XML (or beginners) & perform simple operations on XML.
  • DOM is an absolute necessity for performing complex operations on XML data. Its learning curve is higher than SimpleXML off course but once you get the hang of it , you will know its very logical.
  • Use XPath for conditional access to data. For serial access (like last book) XPath is not needed (but u can use it) since I can use normal DOM / SimpleXML node access.

Ref :
IBM : XML Guide for PHP Developers – Part 2
http://www.devx.com/webdev/Article/41975/1954


PHP : XML QueryLog (Add/Edit)

Logging is absolutely essential to keep track of your system.
I created the below function to keep track of any database queries which failed. Since 1 of the reasons for this could be a loss of database connectivity, keeping a XML based log was more logical than a database log.

For further examples of adding/editing a XML file, check out my other post :
PHP : Create Add Edit Modify Search a XML File via SimpleXML , DOM & XPath

Note :

  • Folder Structure :
    The XML file will have be in a folder in which Y-M-d structure will be maintained. (eg : Today is 2010-05-29 so the XML file will be in inside LOGS/2010/05/29).
  • File Structure :
    <?xml version="1.0"?>
    <querylog>
        <query>
            <timestamp>2008-01-12 19:05:17</timestamp>
            <query>SELECT a,b FROM master WHERE flag='1</query>
            <error>You have an error in your SQL syntax</error>
            <serverip>182.178.2.35</serverip>
            <hostip>122.111.123.121</hostip>
            <dbserver>182.178.2.57:1204</dbserver>
            <dbname>testdb</dbname>
            <filename>/data/test.php</filename>
        </query>
    </querylog>

Code :

/**
*	fn_QueryLog()
*	Internally called to Log Query.
*      	@author 	Rohit (quest4knowledge.wordpress.com)
*
*	@param   	string	$sql	Query
*	@param  	string	$path	Existing Folder of Query Logging
*	@return 	NULL
*/
function fn_QueryLog($sql,$path='')
{
    if(!$path){
        $path 		= rtrim($_SERVER['DOCUMENT_ROOT'],'/').'/LOGS';
    }
    $folders 	= date("Y")."/".date("m")."/".date("d");
    $path       = folderCreator($path,$folders); //defined below
    $filename 	= $path."/querylog.xml"; //XML File Name
    
    $arr['timestamp'] 	= date('Y-m-d H:i:s');
    $arr['query'] 	= $sql;
    $arr['error'] 	= @mysql_error();
    $arr['serverip'] 	= $_SERVER['SERVER_ADDR'];
    $arr['hostip'] 	= $_SERVER['REMOTE_ADDR'];
    $arr['dbserver'] 	= $this->dbserver; // Your DB Server name
    $arr['dbname'] 	= $this->dbname;	// Your DB Name
    $arr['filename'] 	= $_SERVER['SCRIPT_NAME'];
    
    $dom = new DOMDocument('1.0');
    if(file_exists($filename)){ //Edit Existing XML File
        $dom->load($filename);
        $root   = $dom->documentElement;
    }else{ //Create XML File if it doesnt exist
        $dom->formatOutput = true;
        $root = $dom->createElement( "querylog" );
        $dom->appendChild($root);
        //chmod($path."/querylog.xml", 0777);
    }
    
    $q = $dom->createElement("query");
    foreach($arr as $key=>$value)
    {
        $element = $dom->createElement($key);
        if($key=='query'||$key=='error'){
            $element->appendChild($dom->createCDATASection($value));	
        }else{
            $element->appendChild($dom->createTextNode($value));
        }
        $q->appendChild( $element );
    }
    $root->appendChild($q);
    $dom->save($filename);
}

/**
*	folderCreator
*	Internally called to Create Folders if they dont exist.
*      	@author 	Rohit (quest4knowledge.wordpress.com)
*
*	@param   	string	$pathExisting	Existing Folder structure..
*	@param  	string	$dirToCreate	Folders to be created.
*	@return 	string	$pathExisting	New Existing Folder structure.
*/
function folderCreator($pathExisting,$dirToCreate)
{
    $getDir = explode("/",$dirToCreate);
    $dirCnt = count($getDir);
    for($i=0;$i<$dirCnt;$i++)
    {
        if($getDir[$i])
        {
            $pathExisting = $pathExisting.&quot;/&quot;.$getDir[$i];
            $pathExisting = str_replace('//','/',$pathExisting);
                if(!is_dir($pathExisting))	
                    if(!mkdir($pathExisting,0777))
                        die($pathExisting);
        }
    }
    return ($pathExisting);
}