Serializing Data to Pass between Perl and PHP

The objective of this task was to determine if data serialized by PHP could be decoded by Perl.

The first step was to create some serialized data.

In this case, the data is being used to define an interface. An associative array was used, with the first element serving to identify the type of data, and the second to contain the details of the interface. The details is an associative array where each element includes a validation string, label, help or error string, default value, and entered value. This could be extended to include i18n and l10n information, as well as a wide variety of other data.

The PHP code serializes the array, echos it, and then does a var_dump.

<?php
$aData=array(
'type'=>'Magic',
'details'=>array(
'url'=>array(
        'validation'=>'/^[\.\w\-]{1,255}$/',
        'label'=>'URL',
        'help'=>'Valid URL is letters, digits, dashes, periods',
        'default'=>'http://default.com',
        'value'=>'http://domain.com'),
'authid'=>array(
        'validation'=>'/^[\.\w\-]{1,255}$/',
        'label'=>'AuthId',
        'help'=>'Valid Id is letters, digits, dashes, periods',
        'default'=>'',
        'value'=>'')
));
$sSerialized=serialize($aData);
echo $sSerialized.PHP_EOL;
var_dump(unserialize($sSerialized));
echo PHP_EOL;

I took the serialized data echoed by PHP and pasted it into a Perl script.

It uses the PHP::Serialization module to unserialize the data. The code posted here is based on http://www.ohmpie.com/serialization, although this is a more limited example, the ohmpie.com page offers serveral differ serialization approaches.

The printAll method prints all the attributes and values for the class. Note that the values can be reached directly through the object.


#!/usr/bin/perl
# Thanks to: http://www.ohmpie.com/serialization/
use strict;
use PHP::Serialization;
use TestClass;
my $encoded='a:2:{s:4:"type";s:8:"Magic";s:7:"details";a:2:{s:3:"url";a:5:{s:10:"validation";s:19:"/^[\.\w\-]{1,255}$/";s:5:"label";s:3:"URL";s:4:"help";s:45:"Valid URL is letters, digits, dashes, periods";s:7:"default";s:18:"http://default.com";s:5:"value";s:17:"http://domain.com";}s:6:"authid";a:5:{s:10:"validation";s:19:"/^[\.\w\-]{1,255}$/";s:5:"label";s:6:"AuthId";s:4:"help";s:44:"Valid Id is letters, digits, dashes, periods";s:7:"default";s:0:"";s:5:"value";s:0:"";}}}';
my $data = PHP::Serialization::unserialize($encoded);
bless($data,'TestClass');
$data->printAll;

print "URL: ".$data->{'details'}->{'url'}->{'value'}."\n";

print "\n";

This is the TestClass package or module. It only includes the top two elements, type and details, PHP::serialize populates the object with the unserialize call.


#!/usr/bin/perl
# Thanks to: http://www.ohmpie.com/serialization/
#       http://www.perlhowto.com/iterate_through_a_hash
#       http://perl.about.com/od/packagesmodules/qt/perlcpan.htm
#       http://search.cpan.org/~bobtfish/PHP-Serialization-0.34/lib/PHP/Serialization.pm
package TestClass;
use strict; 

#The Constructor
sub new {

        my $obj = {
                type => undef,
                details => undef };
        bless($obj);

        return $obj;
}

sub printAll {
        my $key=undef;
        my %hash=undef;
        my $innerkey=undef;
        my %innerhash=undef;
        my $self=shift;
        my $value=undef;
        my $innervalue=undef;
        print "Type: " .
        $self->{'type'}."\n";
        %hash=%{$self->{'details'}};
        while (($key,$value) = each %hash )
        {
                print "key: $key\n";
                %innerhash = %{$value};
                while (($innerkey,$innervalue) = each %innerhash )
                {
                        print "\t$innerkey: $innervalue\n";
                }
        }
        print "\n";
}

1;

This approach allows data to be stored serialized in a database and read and updated by either Perl or PHP. The structure of the data can change, but the database schema would remain the same.

HTTP Blacklist - Http:BL PHP Code - Generic

This is a generic PHP script that can be used with Http:BL. Http:BL can be used to block requests to a web site based on the IP address. There are several configuration settings that allow you to adjust the performance. In the code below, any IP address identified as suspicious by Project Honey Pot, active within the past 30 days, or with a threat score 100 or greater is blocked.

The easiest way to use it is to include it into the top level of the application, for example:

require_once 'bl.php';

This code just logs the requests and the scores. Once you’re comfortable with it, you can use it to redirect unwanted visitors to a 403 page, or down the rabbit hole.


<?php
/*
abcdefghijkl.2.1.9.127.dnsbl.httpbl.org

Response:
Octet 1: 127 or indicates error
Octet 2: # of days since last activity
Octet 3: Threat score (0=No threat, 255=Extreme threat)
Octet 4: Visitor type
*/

define ('httpBL_API_key','!-- YOUR KEY HERE --!');
define ('httpBL_URL','dnsbl.httpbl.org');
 
/* These are the settings which control which visitors are blocked */
define ('DAYS_SINCE_LAST_ACTIVITY',30);  /* Active within this many days prior will be blocked */
define ('MAX_THREAT_SCORE',100);         /* Anything over this threat score will be blocked */
define ('MAX_TYPE_VALUE',1);             /* Type of visitor - this isn't really bitmapped */
define ('VISITOR_MAP',3);
 
$aOctetMap=array(
'127'=>0,
'DAYS_SINCE_LAST_ACTIVITY'=>1,
'MAX_THREAT_SCORE'=>2,
'VISITOR_MAP'=>3
);
 
$aVisitorType=array(
0=>'Search Engine',
1=>'Suspicious',
2=>'Harvester',
4=>'Comment Spammer',
8=>'[Reserved for Future Use]',
16=>'[Reserved for Future Use]',
32=>'[Reserved for Future Use]',
64=>'[Reserved for Future Use]',
128=>'[Reserved for Future Use]'
);
         
$aSearchEngineSerials=array(
0=>'Undocumented',
1=>'AltaVista',
2=>'Ask',
3=>'Baidu',
4=>'Excite',
5=>'Google',
6=>'Looksmart',
7=>'Lycos',
8=>'MSN',
9=>'Yahoo',
10=>'Cuil',
11=>'InfoSeek',
12=>'Miscellaneous'
);
$sBL=httpBL($_SERVER['REMOTE_ADDR']);
if ($sBL!==null) 
        /* Write out the information to a text file so you can see what is happening */
        file_put_contents('output.txt',$_SERVER['REMOTE_ADDR'].' '.$sBL.PHP_EOL,FILE_APPEND);
        /* Once you are comfortable with your code and settings, you can redirect unwanted visitors elsewhere */
         
function httpBL($sIP)
{
        global $aOctetMap;

        $sOctets=implode('.',array_reverse(explode('.',$sIP)));
        $sURL=httpBL_API_key.'.'.$sOctets.'.'.httpBL_URL;
        $aResult=dns_get_record($sURL,DNS_A);
        if (isset($aResult[0]) && isset($aResult[0]['ip']))
        {
                $aResultOctet=explode('.',$sResult=$aResult[0]['ip']);
                if ((int)$aResultOctet[$aOctetMap['VISITOR_MAP']]<MAX_TYPE_VALUE) return null;
                if ((int)$aResultOctet[$aOctetMap['MAX_THREAT_SCORE']]>=MAX_THREAT_SCORE) return $sResult;
                if ((int)$aResultOctet[$aOctetMap['DAYS_SINCE_LAST_ACTIVITY']]<=DAYS_SINCE_LAST_ACTIVITY) return $sResult;
        }
        return null;
}

The advantage of this approach is that after an IP address has been cleared or cleaned up, access is restored without admin action, so blocked addresses aren’t blocked forever, only for a month or so while they are potentially harmful. The .htaccess Allow,Deny configuration can also be used, but it must be manually maintained, by checking the stats frequently and determining the owner and extent of the IP address block.

eZ publish - Disable ezinfo with .htaccess

The ezinfo module exposes the version number and other key information about an eZ publish installation.

It can be disabled through the eZ publish settings by adding these lines to override/site.ini.append.php:

[SiteAccessRules]
Rules[]=access;disable
Rules[]=module;ezinfo

An additional level of protection can be achieved using a RewriteRule, like so:

RewriteRule ^ezinfo.* http://domain.com/ [L]

In this case, requests for ezinfo will redirect to the home page, in effect they will appear to be ignored.

Other endpoints which may be used:

  • A server level 403 (access denied) or 404 (page not found) page. If this is the only page that gets these errors, people will still know it is an eZ site.
  • The ‘Error kernel (20)’ page, if it has been customized to act as a 404 page. Ending on this page, without customizing it doesn’t achieve much, since people familiar with eZ will be able to identify it as an eZ system by the message text.
  • A redirect off the server, strictly to frustrate the requester.
  • A bogus page with false information, which may be helpful in identifying harvesters.

Adding a jQuery MP3 Player in to eZ publish

I’ve been wanting to add a cross-browser audio player into a site for a while and I finally found a few minutes to find a solution and apply it.

A quick Google found the link above, which includes good demos and examples.

Files:

http://www.sean-o.com/files/singlemp3player.zip
http://www.sean-o.com/jquery/jmp3/jquery.jmp3.js

Download the files and place them in the design/site/javascript/mp3 directory, where site is the name of the siteaccess. Unzip the zip file.

Edit jquery.jmp3.js and ensure the path names match. The site will probably have to change.


var playerpath = "/design/site/javascript/mp3/";  

Update design.ini.append.php to add the jQuery MP3 code in.

settings/siteaccess/site/design.ini.append.php

[JavaScriptSettings]
JavaScriptList[]=mp3/jquery.jmp3.js

I updated design/site/override/templates/page_layout.tpl to use jQuery from the jQuery CDN.


<script type="text/javascript" src="http://code.jquery.com/jquery-1.5.1.min.js"></script>

I also added the player load code directly into page_layout.tpl, since it was compact. A better approach is probably to add it in as a footer script using the admin interface.

<script type="text/javascript">
$(document).ready(function(){
$(".mp3").jmp3({
/*backcolor: "000000",
forecolor: "22ff22",*/
width: 400,
showdownload: "false",
showfilename: "false"
});
});
</script>

Finally, I override the line/file template, testing to see if the filename ended in .mp3. If the file is an .mp3, the player code is added. In hindsight, a more graceful solution would be to create a custom class for .mp3s, but this works fine.

design/site/override/templates/line_file.tpl

{def $attr=$node.data_map.file}
        {def $fileurl=concat( 'content/download/', $attr.contentobject_id, '/', $attr.id,'/version/', $attr.version , '/file/', $attr.content.original_filename|urlencode )}
        {if $fileurl|ends_with('.mp3')}<span class="mp3">{$fileurl|ezurl('no','full')}</span>{/if}
        {undef $attr}{undef $fileurl}

Many thanks to ’sean-o’ - see the link above.

I tested it on Windows and CentOS, with FireFox 3+, it works really nicely.

As a side note, while working on this, I needed to add the http:// to the URL, and it could not be encapsulated in double quotes, since the name is not assigned in an href or src attribute. eZ has two nice optional parameters for the ezurl function, the first indicating what type of quotes to use (in this case none), and whether to create a full URL or relative (in this case full).

Label with Every Font - ImageMagick

The goal of this adventure was to find the font that looked the best on a Massachusetts license plate, using ImageMagick.

I got the list of fonts using -list type fonts. This was run on two servers with different versions of ImageMagick, so there are two different ways to get the font list. Pick the one that works for you, or make your own.

The license plate blank came from R.T’s Blank Plates.

# This isn't worth automating, you will need to edit the font_list to strip out extra lines
#convert -list type fonts | cut -f1 -d ' ' | sort | uniq > font_list
# If the above won't work, try the next line
#convert -list font | grep 'Font:' | cut -f 2 -d ':' | tr -d ' ' > font_list
for f in $(cat font_list); do
echo $f
convert  ma1987.jpg -compose srcOver -gravity center \( -background transparent -fill "#7c2128" -strokewidth 1 -stroke "#777777" -font "$f" -pointsize "72" label:TAGLNZ -resize 230x -trim -sharpen 0x1.0 \) +composite MA-$f.png
done

This is one of the 270+ images that were created:

MA - Helvetica-Narrow

This is a good example of centering a label. The command line begins with the convert command, followed by the blank plate. ‘compose srcOver’ and ‘gravity center’ position the image labeled in parenthesis over the plate, and ‘+composite’ assembles the image.

Many thanks to the ImageMagick examples.

You can create your own license plate avatar at taglinez.com.