PHP one-liners on the CLI

PHP Code

After checking out a page called Perl one-liners and reading how you could execute Perl inline on the CLI, I decided to try and replicate some grep functionality using PHP one-liners for fun.

Interestingly, PHP seems quite slow compared to other tools for my particular task, so I probably won’t be using these approaches outlined below in daily practice. :-)

Here are some stats for a search through all files in the current directory for words with ‘foo’ in them:

time to search using PHP:

username@host:~$ time php -r '$s="foo";$fs=scandir(".");foreach($fs as $f){$ls=file($f);foreach($ls as $l){if(strpos($l,$s)!==false)echo "$f:$l";}}'
filename.txt:football season is approaching
 
real	0m0.013s
user	0m0.012s
sys	0m0.000s

time to search using Perl:

username@host:~$ time perl -ne 'print "$ARGV:$_" if /foo/' *
filename.txt:football season is approaching
 
real	0m0.003s
user	0m0.000s
sys	0m0.000s

time to search using grep:

username@host:~$ time grep -H foo *
filename.txt:football season is approaching
 
real	0m0.002s
user	0m0.000s
sys	0m0.000s

As you can see, to use the one liner technique it appears to be as simple as “compressing” your scripts down to a single line, making sure they are shell friendly, and executing them with the “-r” option. Some other ones that I worked out with PHP are below:

to search for ‘foo’ and print matching lines in a single file

php -r '$s="foo";$ls=file("filename");foreach($ls as $l){if(strpos($l,$s)!==false)echo$l;}'

to search for ‘foo’ and print matching lines in all files in the current directory

php -r '$s="foo";$fs=scandir(".");foreach($fs as $f){$ls=file($f);foreach($ls as $l){if(strpos($l,$s)!==false)echo$l;}}'

to search for ‘foo’ and print matching lines recursively from the current directory

php -r '$s="foo";$t=new RecursiveDirectoryIterator(".");foreach(new RecursiveIteratorIterator($t) as $f){$ls=file($f);foreach($ls as $l){if(strpos($l,$s)!==false)echo$l;}}'

Visualizing Motion

The programmability of the Raspberry Pi comes in handy when you want to change the behavior of a circuit without moving a single wire. In this case, I decided the data I was logging with my former motion detection script was largely useless because it only ever recorded when a motion event occurred, but didn’t hint to how long it had happened for.

So, while I admit the new method probably isn’t the -best- way there is, I believe it to be incrementally better. :-) The main difference being that “sleep” is called for half a second in the mix to allow for the line to start at bottom, progress to top, and then back down after the event occurs. I suppose it is inaccurate in that motion didn’t actually happen exactly in this manner, but it does allow for a nicer graph. Google Chart Tools is used along with the PHP built-in web server effectively piping the “data.js” log file to Google for displaying. I know the Pi has to be online…

Finally every evening at 23:59, cron runs a maintenance script and moves the data around for archiving (I love this little linux box). My thoughts on further improvements have been pointing me toward PHPlot instead of the Annotated Time Line from Google or maybe even utilizing kst. Also I would like to avoid that half second delay in future revisions… oh, and I haven’t tested what happens if I dance around in front of the thing right at midnight. :-)

source for motion.sh

#
#!/bin/bash
function setup {
  gpio export 17 out
  gpio -g write 17 1
  gpio export 18 in
  start=0
  echo The PIR sensor is initializing and calibration has begun.
  i=0; while [ $i -lt 40 ]; do i=$(($i+1)); echo $i; sleep 1; done
}
 
function loop {
  while true
  do
    if [ `gpio -g read 18` -eq 1 ]; then #PIR sensor activated
      if [ $start -eq 0 ]; then
        echo '[new Date('`date +"%Y, "`$((`date +%m`-1))`date \
          +", %d, %H, %M, %S"`'), 0],' | tee -a \
          /opt/GoogleVisualization/app/data.js
        sleep .5
        echo '[new Date('`date +"%Y, "`$((`date +%m`-1))`date \
          +", %d, %H, %M, %S"`'), 1],' | tee -a \
          /opt/GoogleVisualization/app/data.js
        start=1;
      fi
    else #PIR sensor de-activated
      if [ $start -eq 1 ]; then
        echo '[new Date('`date +"%Y, "`$((`date +%m`-1))`date \
          +", %d, %H, %M, %S"`'), 1],' | tee -a \
          /opt/GoogleVisualization/app/data.js
        sleep .5
        echo '[new Date('`date +"%Y, "`$((`date +%m`-1))`date \
          +", %d, %H, %M, %S"`'), 0],' | tee -a \
          /opt/GoogleVisualization/app/data.js
        start=0;
      fi
    fi
  done
}
 
setup; loop

 
excerpt of data.js

[new Date(2012, 10, 28, 08, 06, 30), 0],
[new Date(2012, 10, 28, 08, 06, 31), 1],
[new Date(2012, 10, 28, 08, 07, 10), 1],
[new Date(2012, 10, 28, 08, 07, 11), 0],
[new Date(2012, 10, 28, 08, 07, 16), 0],
[new Date(2012, 10, 28, 08, 07, 17), 1],
[new Date(2012, 10, 28, 08, 07, 22), 1],
[new Date(2012, 10, 28, 08, 07, 23), 0],

 
source for index.php

<?php
$hostname='bb.local';
$directory='/opt/GoogleVisualization/app/';
?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type"
    content="text/html; charset=utf-8" />
  <title>Karl's Passive Infrared Sensor Graph</title>
  <script type="text/javascript" 
    src="http://www.google.com/jsapi"></script>
  <script type="text/javascript">
    google.load('visualization', '1', {packages: 
      ['annotatedtimeline']});
    function drawVisualization() {
      var data = 
        new google.visualization.DataTable();
 
      data.addColumn('datetime', 'Date');
      data.addColumn('number', 'Status');
 
      data.addRows([
        <?php include ('data.js'); ?>
      ]);
 
      var annotatedtimeline = new
        google.visualization.AnnotatedTimeLine(
        document.getElementById('visualization'));
        annotatedtimeline.draw(data, 
        {'displayAnnotations': true});
    }
 
    google.setOnLoadCallback(drawVisualization);
 
  </script>
</head>
<body style="font-family: Arial;border: 0 none;">
  <h1>Karl's Passive Infrared Sensor Graph</h1>
  <div id="visualization" style="width: 900px; height: 300px;">
  </div>
  <br />
  <a href="http://<?php echo $hostname ?>/archive">Archive</a>
</body>
</html>

 
source for the maintenance script

#!/bin/bash
directory=$(date +"%Y-%m-%d")
sleep 60 #wait until midnight, cron is set for 23:59 as this keeps the directory names and dates aligned
mkdir /opt/GoogleVisualization/app/archive/$directory
mv /opt/GoogleVisualization/app/data.js /opt/GoogleVisualization/app/archive/$directory/
cp -pr /opt/GoogleVisualization/app/index.php /opt/GoogleVisualization/app/archive/$directory/

Drupal Modules

I recently completed a project for a customer that afforded me the opportunity to dive into Drupal on better terms. On my first introduction to the software several years back (and Joomla for that matter) I determined I would be able to use my cross-browser theming skills more effectively if I chose WordPress as a base CMS.

This time around I was able to spend a considerable chunk of time reading the documentation (especially around the Theming Guide) and examples on other’s sites. Some topics online seemed incomplete so I did end up reviewing some chapters in a few books on Drupal 7 in particular. In my mind it seems like the developers of WordPress and Drupal are migrating toward each other in feature sets, but delivering solutions from different perspectives.

WordPress appears to be geared more toward out of the box social publishing, with an easy installer, and an easy updater. It can be pushed in almost any direction, but doesn’t seem to be the goal of the software creators. Drupal on the other hand feels more like a collection of building blocks for a web database. While Drupal has fields, blocks, regions, views, and fine grained permissions with roles… URL aliases require a module to automate their selection. There’s even a module to hook up Filemaker Pro and Drupal.

Back to the modules:

I utilized the following:

For spam free contact forms (almost):

For easy page editing:

For dynamic content:

For development and style:

Post via script

I just whipped up some PHP and threw it in the root of a brand new WordPress 2.9.2 install:

<?php
include_once('wp-config.php');
include_once('wp-load.php');
include_once('wp-includes/wp-db.php');
 
$my_post = array();
$my_post['post_title'] = 'My post';
$my_post['post_content'] = 'This is my post.';
$my_post['post_status'] = 'publish';
$my_post['post_author'] = 1;
 
wp_insert_post( $my_post );
?>

Voila. The post appeared when navigating to the .php file.

See: http://codex.wordpress.org/Function_Reference/wp_insert_post.

For more creativity, get into the database: http://codex.wordpress.org/Function_Reference/wpdb_Class

iUI and the iPhone

My employer recently purchased a set of iPhones from AT&T for those in the workforce that have a need for such a thing. One of our first priorities was getting our rolodex accessible (read only) from the road. The main problem is that the data is in a restrictive, old school database. Until we can find time to move it into a more open platform I did the following:

  • Set up a routine for dumping the rolodex into a flat xml file monthly
  • Coded the searching of the the data using PHP and SimpleXML
  • Coded the cookie management (sessions) and most important, a “remember me” feature (because Safari doesn’t remember passwords on the iPhone)
  • Found this lovely library for creating iPhone compatible user intarfaces via the web (read, looks like a native app): iUI (User Interface Library for Safari development on iPhone)

Checkout the screenshots:

Login  Search  Results  Info

It’s pretty cool, because if the contact in the rolodex has a telephone number, address, email address, or webpage associated with them, the data will be displayed and linked to iPhone friendly functions… For example, the telephone number, when clicked on will provide a call button. An address clicked on will link to the built in maps app. Email links open up directly in the built in mail app. Finally, of course, webpages openup in Safari.

So here’s for getting the world more connected… one app at at time.

Goldfish and forged spam

Recently I had the goldfish autoresponder (vacation responses / email auto reply) setup for a user for about one week. Checking their inbox about half way through this time period revealed it having over 47,000 unread messages. What was happening is that spammers were sending email with forged headers. Have you ever received a spam message that apparently has been sent from yourself?

I suppose it can be accomplished via a variety of ways, however I was able to reproduce this particular issue via generating one of these tasty spam mails via the following (all internally of course… I am not a spammer):

telnet smtp.example.com 25

and then issuing these commands:

ehlo workstation.example.com
mail from:
rcpt to:
data
From: 
To: 
Subject: testing a loop
Message text
.
quit

Notice the mail is being sent to the user… and from the user…

  1. The server would receive the email addressed to emailuser@example.com
  2. goldfish would parse the message and notice it needed to respond to… emailuser@example.com
  3. The mail was delivered
  4. Rinse, wash, repeat

The source of the message looked something like this:

root@server:/var/local/vmail/example.com/emailuser# cat new/1220557062.P6882Q0M652544.server,S=1082
Return-Path: 
Delivered-To: emailuser@example.com
Received: from localhost (localhost [127.0.0.1]) by server.example.com (Postfix) with ESMTP id 923E9185F7 for ; Thu, 4 Sep 2008 15:37:42 -0400 (EDT)
X-Virus-Scanned: Debian amavisd-new at server.example.com
Received: from server.example.com ([127.0.0.1]) by localhost (server.example.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id q3tScOaitRoS for ; Thu, 4 Sep 2008 15:37:42 -0400 (EDT)
Received: from workstation.example.com (workstation.example.com [xx.xxx.xxx.xx]) by server.example.com (Postfix) with ESMTP id B89E1185EB for ; Thu, 4 Sep 2008 15:37:25 -0400 (EDT)
From: 
To: 
Subject: testing a loop
Message-Id: 
Date: Thu, 4 Sep 2008 15:37:25 -0400 (EDT)
Message text

and to prevent goldfish from causing havoc on the particular inbox (or mitigating what was already done… and preventing future issues), I added the following PHP:

//strip the line break from $address for checks
$addressCheck = substr($address,0,strlen($address)-1);
if ($addressCheck==$email)
{
	$log-&gt;addLine("Email address from autoresponder table  
	is the same as the intended recipient! Not sending the 
	mail!");
	break;
}

just before letting the mail being sent…

mail($address, $subject, $message, $headers);

I love goldfish. It’s like a do it yourself autoresponder! Keep in mind, this code works on Version 002, patch level 1, but could very well not work on any future releases (there have been indications that a newer version is in the works). Maybe I will post a few more tweaks in upcoming posts if the latest stable stays around for much longer.

Autoresponders – a loop

This past week I encountered an interesting situation between two web applications I work with regularly. The first is the goldfish autoresponder for postfix. The second is RT: Request Tracker.

The situation went something like this:

  • I had a ticket in RT that I wanted to resolve.
  • I set the form to cc the comment to a group of users who were interested in the details of the resolution.
  • I applied the ticket in RT.
  • RT cc’ed the users about the resolution.
  • One of the users had an autoresponder setup using goldfish, so it emailed back to RT about the user’s absence.
  • RT opened a ticket with the content of the email from the autoresponder, faithfully attaching the subject explaining the user’s absence.
  • RT then responded to the user’s email account about the new ticket’s creation.
  • Again goldfish autoresponds to a message from RT, creating a loop.

Every five minutes a new ticket was being created in RT because of goldfish’s configuration and cron job being set to run that often. I caught the cycle happening when the incoming queue of tickets had three or four created with their subjects typical of those created by an autoresponder.

reCAPTCHA plugin error messages

By default, on two of my installs of reCAPTCHA Plugin for WordPress – v2.7, I receive no error message if the captcha is entered incorrectly… the user of the weblog is to assume that they made a mistake I guess…

That is until I wrote this script to check for error messages being passed around on the URL by the plugin:

if (window.location.search != "") {
	var searchArray = window.location.search.split("&amp;");
	for (var i=0; i &lt; searchArray.length; i++) {
		var searchSubArray = searchArray[i].split(&quot;=&quot;);
		if (searchSubArray[0] == &quot;rerror&quot; &amp;&amp; 
		searchSubArray[1] == &quot;incorrect-captcha-sol&quot;) {
			document.write(&quot;<p>The two words in the picture were 
			typed incorrectly.</p>");
		}				
	}
}

Just drop that snippet into your “comments.php” template. When the captcha is filled in incorrectly, the plugin adds “rerror=incorrect-captcha-sol” to the url. This checks for that string, and if found, writes an error message in red.