server | Eric's Drupal Blog

Content tagged with: server

Eric's picture

Configuring a server to parse email via a PHP script

In this tutorial I'll show how you can setup a server to parse email with a PHP script. This tutorial assumes that your server is configured to receive email (I wrote this using a virtual machine running postfix).

The first thing you'll need to do is configure an alias to direct email to a PHP script (instead of an email box). I added the following entry to the bottom of my /etc/aliases file and then ran the "newaliases" command to refresh my aliases database:

phpscript: "|php -q /usr/local/bin/email.php"

The above entry will pipe email sent to phpscript@MYDOMAIN to the designated PHP script.

And here's the script:

#!/usr/bin/php
<?php

// fetch data from stdin
$data = file_get_contents("php://stdin");

// extract the body
// NOTE: a properly formatted email's first empty line defines the separation between the headers and the message body
list($data, $body) = explode("\n\n", $data, 2);

// explode on new line
$data = explode("\n", $data);

// define a variable map of known headers
$patterns = array(
 
'Return-Path',
 
'X-Original-To',
 
'Delivered-To',
 
'Received',
 
'To',
 
'Message-Id',
 
'Date',
 
'From',
 
'Subject',
);

// define a variable to hold parsed headers
$headers = array();

// loop through data
foreach ($data as $data_line) {

 
// for each line, assume a match does not exist yet
 
$pattern_match_exists = false;

 
// check for lines that start with white space
  // NOTE: if a line starts with a white space, it signifies a continuation of the previous header
 
if ((substr($data_line,0,1)==' ' || substr($data_line,0,1)=="\t") && $last_match) {

   
// append to last header
   
$headers[$last_match][] = $data_line;
    continue;

  }

 
// loop through patterns
 
foreach ($patterns as $key => $pattern) {

   
// create preg regex
   
$preg_pattern = '/^' . $pattern .': (.*)$/';

   
// execute preg
   
preg_match($preg_pattern, $data_line, $matches);

   
// check if preg matches exist
   
if (count($matches)) {

     
$headers[$pattern][] = $matches[1];
     
$pattern_match_exists = true;
     
$last_match = $pattern;

    }

  }

 
// check if a pattern did not match for this line
 
if (!$pattern_match_exists) {
   
$headers['UNMATCHED'][] = $data_line;
  }

}

?>

At this point in the code, the body of the message will be contained in the $body variable and the headers will be in $headers.

Here is an example of the parsed headers (using print_r()):

Array
(
    [UNMATCHED] => Array
        (
            [0] => From root@Eric-Centos.localdomain  Sun Jan 10 21:49:50 2010
        )

    [Return-Path] => Array
        (
            [0] => <root@Eric-Centos.localdomain>
        )

    [X-Original-To] => Array
        (
            [0] => phpscript
        )

    [Delivered-To] => Array
        (
            [0] => phpscript@Eric-Centos.localdomain
        )

    [Received] => Array
        (
            [0] => by Eric-Centos.localdomain (Postfix, from userid 0)
            [1] => id 4D03F30131; Sun, 10 Jan 2010 21:49:50 -0500 (EST)
        )

    [To] => Array
        (
            [0] => phpscript@Eric-Centos.localdomain
        )

    [Subject] => Array
        (
            [0] => This is the subject
        )

    [Message-Id] => Array
        (
            [0] => <20100111024950.4D03F30131@Eric-Centos.localdomain>
        )

    [Date] => Array
        (
            [0] => Sun, 10 Jan 2010 21:49:50 -0500 (EST)
        )

    [From] => Array
        (
            [0] => root@Eric-Centos.localdomain (root)
        )

)

Now, you have all the email headers and message body parsed. You can do whatever your heart desires with the data, like insert it into a database or even create nodes!

gradient spacer
Eric's picture

Setting up NAT and port forwarding to connect to a VirtualBox virtual machine for LAMP development

I recently got a new MacBook Pro laptop (awesome!) and went through my usual rigmarole of setting up a new [VirtualBox] virtual machine for LAMP development. In previous situations I used bridged network connections which allow my virtual machine to have its own network connection, and acquire an IP address via DHCP. Now that I plan on being more mobile, I was concerned about having a static IP address for my virtual machine (for samba connections, scripting, and any other processes that relies on a static IP address). I decided to explore alternative virtual network connections and changed my virtual NIC to use NAT (the default network connection for VirtualBox). This configuration establishes a virtual NAT for your virtual machines which is great, but the downside is I know have to setup port forwarding to connect to my virtual machine. In bridged network configurations, I could simply SSH or use Samba to connect to my virtual machine by IP address. With NAT I have to setup port forwarding for the services I need to connect to. Initially I decided to setup port forwarding for SSH (port 22) and HTTP (port 80). While my virtual machine was powered down, I executed the following commands. NOTE: you'll have to replace "Centos" with the name of your virtual machine.

$ VBoxManage setextradata "Centos" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/Protocol" TCP
$ VBoxManage setextradata "Centos" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/GuestPort" 22
$ VBoxManage setextradata "Centos" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/HostPort" 2222
$ VBoxManage setextradata "Centos" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/GuestPort" 80
$ VBoxManage setextradata "Centos" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guesthttp/HostPort" 8080

Now, I can SSH to my virtual machine..

$ ssh -p 2222 Eric@localhost

Or, connect to Apache by browsing to http://localhost:8080

The benefit of this network configuration allows me to travel anywhere with my laptop, use any type of network connection, and not have to worry about changing the way I connect to my virtual machine for development.

gradient spacer
Eric's picture

Upgrading PHP to version 5.2.6 on Centos via YUM

This morning, I encountered a PHP fatal error on my development environment. Upon further inspection, one of my third party modules (XML Sitemap) required a later version of PHP. A fresh installation of Centos 5.3 comes with version 5.1.6 of PHP. Here is an easy way to upgrade PHP to a later version by using the Utter Ramblings Yum repository.

I created a new yum repo file:

$ sudo emacs /etc/yum.repos.d/utterramblings.repo

# FILE CONTENTS - START
[utterramblings]
name=Jason's Utter Ramblings Repo
baseurl=http://www.jasonlitka.com/media/EL$releasever/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://www.jasonlitka.com/media/RPM-GPG-KEY-jlitka
# FILE CONTENTS - END

Ran a yum update:

$ sudo yum update
# ...snip...
Updated: apr.i386 0:1.2.12-2.jason.1 apr-util.i386 0:1.2.12-5.jason.1 curl.i386 0:7.15.5-2.1.el5_3.5 httpd.i386 0:2.2.8-jason.3 ksh.i386 0:20080202-2.el5_3.1 mod_ssl.i386 1:2.2.8-jason.3 mysql.i386 0:5.0.58-jason.2 mysql-server.i386 0:5.0.58-jason.2 pcre.i386 0:7.6-jason.1 php.i386 0:5.2.6-jason.1 php-cli.i386 0:5.2.6-jason.1 php-common.i386 0:5.2.6-jason.1 php-gd.i386 0:5.2.6-jason.1 php-mbstring.i386 0:5.2.6-jason.1 php-mssql.i386 0:5.2.6-jason.1 php-mysql.i386 0:5.2.6-jason.1 php-odbc.i386 0:5.2.6-jason.1 php-pdo.i386 0:5.2.6-jason.1 php-pear.noarch 1:1.6.2-1.jason.1 php-xml.i386 0:5.2.6-jason.1 php-xmlrpc.i386 0:5.2.6-jason.1 subversion.i386 0:1.4.4-jason.1 tzdata.noarch 0:2009k-1.el5
Complete!

After updating all these packages, I checked out my new PHP version:

$ php -v | head -1
PHP 5.2.6 (cli) (built: May  5 2008 10:32:59)

Now, my PHP fatal error has been resolved.

NOTE: This blog entry is a re-post of a previous article.

gradient spacer
Eric's picture

Configure your development server to deliver all mail locally

Back in September 2008, I wrote an article on how to configure your virtual machine to deliver email locally (using postfix, cyrus, imap, and sasl). I've had to revisit this article recently to test some bulk emailing functionality. I wanted to change my email server configuration to deliver all email locally to ensure clients and coworkers do not receive test emails. After reading a bunch of web articles, I decided to use Postfix's transport functionality (located /etc/postfix/transport). This configuration file allows you to map email addresses and hostnames to message delivery transports.

I edited this file (/etc/postfix/transport) and added the following to the end of the file:

* discard:

I then edited my postfix configuration file (/etc/postfix/main.cf) and added the following:

transport_maps = hash:/etc/postfix/transport
always_bcc = eric

Reload the transport and restart postfix using the following commands:

postmap /etc/postfix/transport
/etc/init.d/postfix restart

The first configuration change discards all outgoing email, and the second automatically BCC's my user. Although this is a drastic configuration change, it does exactly what I want: it ensures that email will never be delivered to real world addresses, and any email sent from my development server will end up in my local inbox.

You may have to tweak these settings to find a configuration that works with your development situation. For instance, if you wanted to continue delivery to a certain domain, you could add the following transport:

your.domain :

gradient spacer
Eric's picture

Setting up Samba and connecting to your Parallels virtual machine

I do all of my development on a Parallels virtual machine 1) to keep my host operating system stable at all times; and 2) so I can run the same operating system as our production servers (to reduce the differences in configuration & chance of a deployment issue). I'm a fan of RPM based operating systems (vs APT) so I prefer Centos. To improve performance I do not run a GUI (KDE, Gnome, etc) and I install the bare minimum set of packages. My linux server philosophy has always been: if you don't use it or don't know what it does, don't install it; and if you don't know it does, Google it. My preferred IDE is Eclipse, so I install that on my host operating system (OSX). So how do I edit my files on my virtual machine? Samba. Here's how I setup a basic samba configuration:

Install Samba (as necessary)

sudo yum install samba

Create a backup of the original samba configuration file, just in case

sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.orig

Here's a basic smb.conf file I use with a description for each config setting:

[global]
    # workgroup should match your network that your host operating system is on
    workgroup = MYWORKGROUP
    # server string is description of samba server
    server string = MY CENTOS VM
    # default security level
    security = user
    # performance tuning
    socket options - TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
[homes]
    # share comment for user's home directories
    comment = Home Directories
    # hides shares to users without permission
    browseable = no
    # allows privileged users to modify files
    writable = yes
[Vhosts]
    # I share my entire vhosts folder
    comment = Vhosts
    # to be more secure, I only allow my primary user from my host operating system access
    valid users = eric
    # allows privileged users to modify files
    writeable = yes
    # this is the path to my Apache vhosts
    path = /var/www/vhosts
    # setting a umask will ensure permissions will be set correctly on files created across a samba share
    directory mask = 775
    create mask = 664

Create a samba user that matches your host operating system

sudo smbpasswd -a eric

Restart Samba

sudo /etc/init.d/smb restart

Now, from your host operating you can connect to your vhosts share and edit your files. From OSX, I use the "connect to server" command in the finder menu and specify the IP address of my virtual machine. The samba share will now be mounted in /Volumes/IPOFYOURVM. When I create a new project in Eclipse, I uncheck the default location and choose to create the project on my virtual machine. tah-dah

gradient spacer Syndicate content