Passing Structured Data from Perl to PHP

After writing many lines of Perl to decode data returned from database queries which must then be passed back to PHP, I found JSON conversion routines which are much faster and more reliable. In addition, unlike my awkward Perl, they work!

::::::::::::::
test.pl
::::::::::::::

#!/usr/bin/perl

use strict;
use JSON::XS;

# Thanks to: http://stackoverflow.com/questions/8463919/how-to-convert-a-simple-hash-to-json-in-perl
my $json=JSON::XS->new->utf8->pretty->allow_nonref;

my %data=('one',1,'two',"bee's",'three',0,'four',('a','monkey','b','cat'));

my $json_text=$json->encode(\%data);
# Escape the single quotes
$json_text=~s/(')/\\$1/g;
# Remove carriage returns
$json_text=~s/(\n)//g;

print<<RETURN;
json=$json_text
RETURN

::::::::::::::
test.php
::::::::::::::

<?php
include 'Zend/Json.php';

$aResult=null;
$aResponseLines=$aResult=array();

$sResponse=`perl test.pl`;

$aResponseLines=explode("\n",$sResponse);
if (count($aResponseLines)>0)
foreach ($aResponseLines as $k => $v)
{
        $e=strpos($v,'=');
        if ($e!==false)
                $aResult[substr($v,0,$e)]=substr($v,$e+1);
}

var_dump($aResult);

var_dump(Zend_Json::decode($aResult['json']));

bash Version Control Check-In

To make it easier to copy code from a development server to a version control server, check the file, then check it in, I created a bash script.

This script is also supported with ssh keys so the password does not need to be entered with each copy request. Thanks to: http://www.thegeekstuff.com/2008/11/3-steps-to-perform-ssh-login-without-password-using-ssh-keygen-ssh-copy-id/

#!/bin/bash

# This script requires three parameters
#       server - The name of the server where the code will be retrieved from
#       file - The name of the file.  In this case, the path is hardcoded.
#       comment - A comment to include when checking in the file

if [ $# -lt 3 ]; then
        echo 'usage:'
        echo '        ~/get.sh server file comment'
else
        # Copy the file
        scp root@$1.domain.com:/opt/system/web/portal/$2 NEW

        # If the files can be compared
        if [ -r NEW -a -r "$2" ]; then

                # Create tmp file for the diff results
                TMP=`mktemp`
                diff NEW "$2" > "$TMP"

                # If the files are different
                if [ $? -ne 0 ]; then
                        more "$TMP"
                        echo -n 'Update? y/[n]? '
                        read
                        if [ $REPLY == 'y' ]; then
                                # Checkout the file
                                cleartool co -nc "$2"
                                # Copy the new file over
                                cp NEW $2
                                # Checkin the updated file
                                cleartool ci -c "$3" "$2"
                        else
                                echo 'no changes made'
                        fi
                else
                        echo 'files are the same'
                fi
                rm $TMP
        else
                echo 'scp failed or files missing'
        fi
fi

Thanks to:
http://www.cyberciti.biz/tips/shell-scripting-bash-how-to-create-temporary-random-file-name.html

Dynamic Banner - js and css

This post provides code to create a dynamic banner which sources images from Flickr.

Using a dynamic banner has several advantages:

  • The banner is assembled dynamically, it is more engaging
  • The images aren’t stored or managed on local servers
  • The banner images can be changed by modifying the images at the source
  • It would be possible to customize the source of the images for demonstrations
  • Clicking on the banner displays the image credits

This is an extension of the code listed in link above. It is running nicely with dojo 1.3.0, tested under IE7, FF11&12, and Chrome 17.

The banner is 160px high, and 1024px wide, it is overlaid with an image which includes a gradient to fade the banner images from full color to white, using transparency. The banner includes an icon for the product on the far right.

#header img,#header a
{
height:160px;
overflow:hidden;
}
#gradient-overlay
{
background:transparent url(images/banner.png) no-repeat;
height:160px;
width:1024px;
position:fixed;
}
#header
{
cursor:pointer;
height:160px;
width:100%;
margin:25px;
overflow:hidden;
}
#dlgCredit div p
{
display:none;
}
#dlgCredit div p:first-of-type,
#dlgCredit div p:nth-child(2)
{
display:block;
}

This is the javascript to create the banner. The remaining code should be collected from the link above.

The image list received from flickr is accessed randomly, using the splice function. This allows each banner to be created differently. Images are added to the banner until the width exceeds the width of the gradient overlay. The image credits are place in a dialog box.

                function gotItems(items, request){
                        var list = dojo.byId("header");
                        if(list){
                                var span=dojo.create("span",{'id':'gradient-overlay'});
                                list.appendChild(span);
                                var width,pick,credit_text='',done=false;
                                width=span.clientWidth;
                                while (!done)
                                {
                                        index=Math.floor(Math.random()*(items.length-1));
                                        pick=items.splice(index,1);
                                        if (pick.length>0)
                                        {
                                                var item=pick[0];
                                                var image = dojo.create("img",
                                                        { "src":flickrStore.getValue(item, "imageUrlMedium"),
                                                        "title": flickrStore.getValue(item, "title"),
                                                        "alt": flickrStore.getValue(item, "title")});
                                                if ((image.width==0)||(image.width>width))
                                                {
                                                        /* Limit the width of the banner */
                                                        dojo.destroy(image);
                                                        if (image.width>width)
                                                                done=true;
                                                        /* You can also continue to see if later images will fit */
                                                }
                                                else
                                                {
                                                        width-=image.width;
                                                        list.appendChild(image);
                                                        var str=flickrStore.getValue(item,'description');
                                                        var n=str.indexOf('');
                                                        n=str.indexOf('',n+1);
                                                        var truncated=str.substr(0,n);
                                                        credit_text+='<div>'+truncated+'</div>';
                                                }
                                        }
                                        else
                                                done=true;
                                }
                                var credit=dojo.create("div",{'id':'credit'});
                                var dlgCredit=new dijit.Dialog({
                                        'id': 'dlgCredit',
                                        'content':credit_text},
                                        'credit');
                                list.setAttribute('title','Click for image credits');
                                list.onclick=function(){dlgCredit.show()};
                                list.appendChild(credit);
                        }

The HTML creates the flickrStore and sets up the header div.

<div dojoType="dojox.data.FlickrStore" jsId="flickrStore"></div>
<div id="header"></div>

This post courtesy of Lyrix, Inc

dojox.data.FlickrStore - Source from favorites

I wanted to use a favorites list on Flickr (http://flickr.com) as a source for images.

dojo 1.3.0’s dojox.data.FlickrStore sources images from a public photo feed:

reg.register("default",function(_2f){return true;},_2d+"photos_public.gne");

Since I only wanted to change the feed URL, I used the following code to indicate that the request should be made to the favorites feed.

	var reg=dojox.data.FlickrStore.urlRegistry;
	reg.unregister("default");
	reg.register("default",function(a){
		return true;
		},"http://api.flickr.com/services/feeds/photos_faves.gne");

Google OAuth and Contacts API - PHP Curl Examples

This code uses Zend Framework’s Zend_Json::decode method, however you can use json_decode if it is available on your version of PHP.

Create the authorization link
When this link is clicked, the site visitor is presented with a page from Google asking if they would like to allow your application access to their data. If they accept, Google will give them a code, which can then be used on the next request. This is run as an installed application, because there are times when data will be requested without user interaction.

$sAuthURL=AUTH_URL;
$aParms=array('response_type'=>RESPONSE_TYPE,
        'client_id'=>CLIENT_ID,
        'redirect_uri'=>REDIRECT_URI,
        'scope'=>SCOPE);
$sLink=$sAuthURL.'?'.http_build_query($aParms);

Request an access and refresh token

        require_once 'Zend/Json.php';
        $sTokenURL=TOKEN_URL;
        $aParms=array(
                'code'=>$_POST['code'],
                'client_id'=>CLIENT_ID,
                'client_secret'=>CLIENT_SECRET,
                'redirect_uri'=>REDIRECT_URI,
                'grant_type'=>AUTHORIZATION_CODE);
        $cURL=curl_init();
        curl_setopt($cURL,CURLOPT_URL,$sTokenURL);
        curl_setopt($cURL,CURLOPT_SSL_VERIFYPEER,TRUE);
        curl_setopt($cURL,CURLOPT_POST, TRUE);
        curl_setopt($cURL,CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($cURL,CURLOPT_POSTFIELDS,$aParms);
        $cResponse=Zend_Json::decode(trim(curl_exec($cURL)));
        curl_close($cURL);                
        $sAccessToken=$cResponse['access_token'];
        $sRefreshToken=$cResponse['refresh_token'];

Use the refresh_token to request a new access_token

                                $sTokenURL=TOKEN_URL;
                                $aParms=array(
                                        'refresh_token'=>$sRefreshToken,
                                        'client_id'=>CLIENT_ID,
                                        'client_secret'=>CLIENT_SECRET,
                                        'grant_type'=>REFRESH_TOKEN);
                                $cURL=curl_init();
                                curl_setopt($cURL,CURLOPT_URL,$sTokenURL);
                                curl_setopt($cURL,CURLOPT_SSL_VERIFYPEER,TRUE);
                                curl_setopt($cURL,CURLOPT_POST, TRUE);
                                curl_setopt($cURL,CURLOPT_RETURNTRANSFER, TRUE);
                                curl_setopt($cURL,CURLOPT_POSTFIELDS,$aParms);
                                require_once 'Zend/Json.php';
                                $cResponse=Zend_Json::decode(trim(curl_exec($cURL)));
                                $sError=curl_error($cURL);
                                curl_close($cURL);
                                $sAccessToken=$cResponse['access_token'];



Request the contact data


                $sContactsURL=CONTACTS_URL.'?access_token='.$sAccessToken;
                $cURL=curl_init();
                curl_setopt($cURL,CURLOPT_URL,$sContactsURL);
                curl_setopt($cURL,CURLOPT_RETURNTRANSFER, TRUE);
                $cResponse=trim(curl_exec($cURL));
                $sError=curl_error($cURL);
                curl_close($cURL);

Parse the data from Google
This code also Zend_Gdata to handle the parsing.

$phone_only=false;

include 'Zend/Gdata.php';

$gdata=new Zend_Gdata();
$feed=$gdata->importString($cResponse);

foreach ($feed as $entry) {
        // Thanks to: http://www.ibm.com/developerworks/opensource/library/x-phpgooglecontact/index.html
        $xml = simplexml_load_string($entry->getXML());
        $obj = new stdClass;
        $obj->id = $entry->id->text;
        if (false===($iSlash=strpos($entry->title->text,'/')))
                $obj->name=$entry->title->text;
        else
                $obj->name = substr($entry->title->text,0,$iSlash);
        if (empty($obj->name)) continue;
        $name = explode(' ',$obj->name,3);
        $obj->first_name = $obj->middle_name = $obj->last_name = '';
        switch (count($name))
        {
                case 1: 
                        $obj->first_name = $obj->name;
                        break;
                case 2: 
                        $obj->first_name = $name[0];
                        $obj->last_name = $name[1];
                        break;
                case 3:
                        $obj->first_name = $name[0];
                        $obj->middle_name = $name[1];
                        $obj->last_name = $name[2];
                        break;
        }
        $obj->phoneNumber = array();
        $obj->phone = array();
        foreach ($xml->phoneNumber as $p) 
        {
                $type = preg_replace('/^[^#]+#(.*)$/','\1',(string) $p['rel']);
                $obj->phoneNumber[] = (string) $p.' ('.$type.')';
                $obj->phone[$type] = array ('phone' => preg_replace('/\D/','',(string) $p), 'type' => strtolower($type) );
        }
        if (empty($obj->phone) && $phone_only) continue;
        $results[$obj->last_name] = $obj;  
}
ksort($results);



This post courtesy of Lyrix, Inc. http://mobiso.com