Category: "PHP"
Passing Structured Data from Perl to PHP
Jun 14th
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']));
Google OAuth and Contacts API - PHP Curl Examples
Apr 26th
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
PHP <-> Perl Bridge using cURL
Jul 18th
Using cURL to submit requests from PHP into Perl allows graceful reuse of code with a system with a robust core of Perl code and a PHP web interface.
The Perl code accepts a module name, sub/function name, and a set of parameters.
It includes the module, then tests for the sub. Then assembles the parameters into a request and calls the Perl code. The code returned may be name value pairs, or PHP, for more complex responses.
This code has been edited for brevity, it is an example, not a ready to use solution.
#!/usr/bin/perl
use strict;
use CGI qw(-compile :cgi);
my $q=CGI->new;
print $q->header('text/plain');
my $m=$q->param('module');
my $s=$q->param('sub');
$m=~s/\W//g;
my $path="$ENV{'APPHOME'}/bin/".$m.".pm";
require $path;
my $ms=$m.'::'.$s;
if (Test($ms))
{
my $x='bridge_'.$m.'("'.$s.'",\%{$q->Vars})';
eval $x;
exit 0;
}
else
{
exit 101;
}
sub Test
{
my $sub_name=$_[0];
return ( defined &{ $sub_name } );
}
sub bridge_PERL_CODE
{
my $r=0;
my $sub=$_[0];
my (%parms)=%{$_[1]};
delete $parms{'module'};
delete $parms{'sub'};
SWITCH: for ($sub)
{
/^getSystemServices$/ && do
{
my %services;
my $status=PERL_CODE::getSystemServices(\%services);
# Sample code to generate PHP
my ($id,$k,$kk,$s,$t);
print '<?php',"\n";
$s='$services=array('."\n";
for my $k ( keys %services )
{
$id=$services{$k}{'id'};
delete $services{$k}{'id'};
$s.='\''.$id.'\'=>array('."\n";
for $kk ( keys %{$services{$k}} )
{
$t=$services{$k}{$kk};
$t =~ s/(['"])/\\$1/g;
$s.="\t".'\''.$kk.'\'=>\''.$t.'\',';
}
$s=substr $s,0,-1;
$s.='),'."\n";
}
$s=substr $s,0,-2;
$s.=');';
print $s,"\n";
print '?>';
$r=$status;
last SWITCH;
};
/^getServiceParms$/ && do
{
my $serviceId=$parms{'serviceId'};
my %parmValues;
my ($status,$msg)=PERL_CODE::getServiceParms($serviceId, \%paramValues);
# Sample code to generate name/value pairs
my ($k,$v);
while (($k, $v) = each(%parmValues))
{
print $k.'='.$v,"\n";
}
print 'status='.$status,"\n";
print 'msg='.$msg,"\n";
$r=$status;
last SWITCH;
};
#DEFAULT
{
# Error - Should never get here
$r=-1;
last SWITCH;
};
}
return $r;
}
<?php
function curl_request($sPost=null,$bHandleAsPHP=false)
{
$cURL=curl_init();
curl_setopt($cURL,CURLOPT_URL,"http://localhost/cgi-bin/bridge.pl");
curl_setopt($cURL,CURLOPT_POST, TRUE);
curl_setopt($cURL,CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($cURL,CURLOPT_POSTFIELDS,$sPost);
$cResponse=trim(curl_exec($cURL));
curl_close($cURL);
return handle_response($cResponse,$bHandleAsPHP);
}
function handle_response($sResponse=null,$bHandleAsPHP=false)
{
if (!$bHandleAsPHP)
{
$aResponseLines=$aResult=array();
$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);
}
}
else
{
$sResponse=str_replace(array('<?php','?>'),'',$sResponse);
$sResponse.="\n".'$vars=get_defined_vars();';
eval($sResponse);
unset($vars['sResponse'],$vars['bHandleAsPHP']);
$aResult=$vars;
}
return $aResult;
}
/* Call across the bridge, expecting PHP in response */
function getSystemServices()
{
return curl_request('module=PERL_CODE&sub=getSystemServices',true);
}
Google Maps API - Distance Calculator - PHP Example
Jul 13th
This code gets the distance, in miles, between two US Zip codes (04429 and 02135). You can substitute other origins and destinations.
<?php
function curl_request($sURL,$sQueryString=null)
{
$cURL=curl_init();
curl_setopt($cURL,CURLOPT_URL,$sURL.'?'.$sQueryString);
curl_setopt($cURL,CURLOPT_RETURNTRANSFER, TRUE);
$cResponse=trim(curl_exec($cURL));
curl_close($cURL);
return $cResponse;
}
$sResponse=curl_request('http://maps.googleapis.com/maps/api/distancematrix/json',
'origins=04429&destinations=02135&mode=driving&units=imperial&sensor=false');
$oJSON=json_decode($sResponse);
if ($oJSON->status=='OK')
$fDistanceInMiles=(float)preg_replace('/[^\d\.]/','',$oJSON->rows[0]->elements[0]->distance->text);
else
$fDistanceInMiles=0;
echo 'Distance in Miles: '.$fDistanceInMiles.PHP_EOL;
Notes
- The preg_replace code discards any text, other than the numeric representation of the distance.
- This was run under PHP 5.2.17, the json_decode function was introduced in version 5.2.0.
- Be sure to include the sensor input, otherwise, you will get a “REQUEST DENIED”
- Also be sure to validate and sanitize any inputs as appropriate.
Refer to the link above for additional information.
PHP Text Highlighter
Jul 13th
This snippet accepts an array of words, and a descriptive name which can be used to reference the words, like so:
$this->scan(array('mysql','css','js','content management system',
'xhtml','xml','rss','html','lamp','ria',
'sugar','php','zend framework','oo','dojo',
'doctrine','javascript','smarty','ez publish'),'skills');
It scans a block of text, and returns matches enclosed in span tags, which can be highlighted using CSS.
private function scan($aWords,$sType)
{
// Thanks to: http://us.php.net/manual/en/function.array-walk.php#103056
array_walk($aWords, create_function('&$val', '$val = \'/(\W)(\'.$val.\')\W)/umi\';'));
$this->data[$sType.'_HTML']=preg_replace($aWords,'\1<span class="found">\2</span>\3',
$this->data['sContent'],1,$this->data[$sType.'_COUNT']);
}
// Used to access the private $data array
public function __get($sName)
{
if(isset($this->data[$sName]))
return $this->data[$sName];
else
return null;
}
To extract the HTML and a count of the matches:
$sOutput=<<<BLOCK
<div id="skills_check">
$oResponse->skills_HTML
<div id="skills_count">
Skills matched: $oResponse->skills_COUNT
</div>
BLOCK;
A match is considered a string with non-word characters immediately before and after. This makes mismatches less likely. For example, ‘oo’ would not match ‘Joomla’, but it would match ‘ oo.’, or ‘,oo and …’.
There can be several scans in a page, using the id of a parent div can allow them to be presented differently, for example:
span.found
{
font-weight:bolder;
}
#skills_check span.found
{
color:#22ff22;
}