PHPMailer NTLM (MS Exchange) SMTP authentication

PHPmailer does not work with NTLM authentication and insists on using mhash() which is deprecated – so you need to edit the file in /extras called ntlm_sasl_client.php

Find the code that checks if mhash() is installed and replace the 3 mhashes with hash instead:

|| !function_exists($function = "mhash")
) {
$extensions = array(
"mcrypt_encrypt" => "mcrypt",
"mhash" => "mhash"

Then replace these three lines:

$unicode = $this->ASCIIToUnicode($password);
$md4 = mhash(MHASH_MD4, $unicode);
$padded = $md4 . str_repeat(chr(0), 21 - strlen($md4));

With the following:

$unicode = iconv('UTF-8', 'UTF-16LE', $password);
$padded = pack('H*', hash('md4', $unicode));

And the library now works. When sending you will need to define a couple of extra bits:

$mail->SMTPSecure = 'ntlm';
$mail->Realm = "yourdomain.com";
$mail->Workstation = "WORKSTATION1";

…obviously replacing the domain and workstation name with your own values.

Convert HTML table to CSV

Just a quick one – I needed a script to convert a table to a csv, so this is what I came up with. See the annotations for notes:

//html table is in variable $report
$report = str_replace(array("\n", "\r"), "", $report); //remove existing line breaks
$report = str_replace('"', '\"', $report); //escape existing quote marks
$csv_lines = explode('</tr>', $report); //explode by end of table row
$csv_report = ''; //define output
  foreach ($csv_lines as $this_line) { //each row
  $csv_cells = explode('</td>', $this_line); //explode by end of table cell
  $csv_newcells = array(); //define new cells
    foreach ($csv_cells as $this_cell) { //each cell
    $this_cell = strip_tags($this_cell); //remove any html tags
    $this_cell = html_entity_decode($this_cell); //remove any html characters
    $this_cell = trim($this_cell); //trim any whitespace
      if (!is_numeric($this_cell)) $this_cell = '"'.$this_cell.'"'; //encapsulate in quotes if it is not a number
    $csv_newcells[] = $this_cell; //add it to the new cell array
    } //foreach cell
  $csv_report .= implode(',', $csv_newcells)."\r\n"; add the new cell line to the output
  } //foreach line
echo $csv_report;

Cover your Paypal fees

I just thought I’d share a formula I worked out a few years ago when a client asked me to make sure his Paypal website payments were covering the Paypal fees – so that he got the full amount he was asking for.

In the UK, Paypal standard fees are 3.4% plus 20p. So if we invoke the magic of algebra, where x is the total and y is the fee, we start with this:

x = (x+y)-(0.034*(x+y))-0.20

I won’t bother taking you through the workings out, but essentially it ends up like this:

y = (17x+100)/483

So if you take your original total (say £100), multiply it by 17 (£1700), then add 100 (£1800), then divide by 483 – you get the fee: £3.73 (rounded up).

To double-check that: £103.73 (total plus fee) times 0.034 plus 0.20 equals… £3.73 (rounded up) – so Paypal will take £3.73 off your £103.73 leaving you with the original figure.

Add custom fonts to WordPress TinyMCE editor with @font-face

The list of fonts in the WordPress visual editor is quite short. There are plugins available to increase it, but I wanted to add my own custom font to the select dropdown.

There’s no plugin hook for this, so it needs a little lateral thinking. Firstly, generate your webfont @font-face in the normal way – I use http://www.fontsquirrel.com/fontface/generator or http://www.font2web.com

Then add the css to your site stylesheet as normal, e.g.

@font-face {
font-family: 'CustomFont';
src: url('fonts/customfont-webfont.eot');
src: local('CustomFont'),
url('fonts/customfont-webfont.eot?iefix') format('eot'),
url('fonts/customfont-webfont.woff') format('woff'),
url('fonts/customfont-webfont.ttf') format('truetype'),
url('fonts/customfont-webfont.svg#webfontnTz28sxq') format('svg');
font-weight: normal;
font-style: normal;
}

There is a plugin hook that adds a custom stylesheet (adding the code content_css: "stylesheet.css",), so we can use that to inject our own code by closing the quote marks first without entering a stylesheet (or you can if you want so that you can use the font in the editor) and then adding what we need, so add this into your theme’s functions.php:

function plugin_mce_addfont($mce_css) {
if (! empty($mce_css)) $mce_css .= ',';
$mce_css .= '",theme_advanced_fonts:"Custom Font=CustomFont,arial,helvetica,sans-serif';
return $mce_css;
}
add_filter('mce_css', 'plugin_mce_addfont');

So the first thing we do is close the double quotes and then leave off the final double quote in our code. This will only give you the one choice of font, however (with a browser backup to Arial etc. in case it doesn’t work).  The full list of fonts you originally had is in the file wp-includes/js/tinymce/themes/advanced/editor-template.js so we need to tack them on the end so that we can use all of them:

function plugin_mce_addfont($mce_css) {
if (! empty($mce_css)) $mce_css .= ',';
$mce_css .= '",theme_advanced_fonts:"Custom Font=CustomFont,arial,helvetica,sans-serif;Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';
return $mce_css;
}
add_filter('mce_css', 'plugin_mce_addfont');

Done.

Process email bounces with PHP

This is a quick script to process email bounces, for example from a mailing list so that users can be flagged up or unsubscribed when they have too many failures.

The actual bounce identification will be done by Chris Fortune’s Bounce Handler, which you can download from:
http://anti-spam-man.com/php_bouncehandler/

We require 3 files from that package:
bounce_driver.class.php
bounce_responses.php
rfc1893.error.codes.php

What this script does is get the bounced emails from a specified mailbox and counts up how many failed emails there are per email address – if the number is at least as many as your threshold value (called $delete), then (you insert your code to unsubscribe the email address or whatever etc. and) the bounced emails are then deleted. You can run the script as a cronjob or call from your mailing list script to tidy up subscriptions.

<?php

# define variables
$mail_box = '{mail.domain.com:143/novalidate-cert}'; //imap example
$mail_user = 'username'; //mail username
$mail_pass = 'password'; //mail password
$delete = '5'; //deletes emails with at least this number of failures

# connect to mailbox
$conn = imap_open ($mail_box, $mail_user, $mail_pass) or die(imap_last_error());
$num_msgs = imap_num_msg($conn);

# start bounce class
require_once('bounce_driver.class.php');
$bouncehandler = new Bouncehandler();

# get the failures
$email_addresses = array();
$delete_addresses = array();
  for ($n=1;$n<=$num_msgs;$n++) {
  $bounce = imap_fetchheader($conn, $n).imap_body($conn, $n); //entire message
  $multiArray = $bouncehandler->get_the_facts($bounce);
    if (!empty($multiArray[0]['action']) && !empty($multiArray[0]['status']) && !empty($multiArray[0]['recipient']) ) {
      if ($multiArray[0]['action']=='failed') {
      $email_addresses[$multiArray[0]['recipient']]++; //increment number of failures
      $delete_addresses[$multiArray[0]['recipient']][] = $n; //add message to delete array
      } //if delivery failed
    } //if passed parsing as bounce
  } //for loop

# process the failures
  foreach ($email_addresses as $key => $value) { //trim($key) is email address, $value is number of failures
    if ($value>=$delete) {
    /*
    do whatever you need to do here, e.g. unsubscribe email address
    */
    # mark for deletion
      foreach ($delete_addresses[$key] as $delnum) imap_delete($conn, $delnum);
    } //if failed more than $delete times
  } //foreach

# delete messages
imap_expunge($conn);

# close
imap_close($conn);

?>

PHP Recursive File Copy Function

I couldn’t find a function online that copies folders recursively in PHP and actually works, so I wrote my own:

function recursiveCopy($src, $dest) {
if (is_dir($src)) $dir = opendir($src);
while ($file = readdir($dir)) {
if ($file != '.' && $file != '..') {
if (!is_dir($src.'/'.$file)) copy($src.'/'.$file, $dest.'/'.$file);
else {
@mkdir($dest.'/'.$file, 0750);
recursiveCopy($src.'/'.$file, $dest.'/'.$file);
} //else
} //if
} //while
closedir($dir);
} //function

To summarise: if the source is a folder, open it and start reading the files. If the files are not folders, copy them straight to the destination, if they are folders, create a new folder at the destination and then run the function again (within itself) for the new folder.

Usage:

recursiveCopy('/home/site/public_html/folder','/home/othersite/public_html/folder');

Javascript (JQuery): Social networking feeds – new Facebook authentication

After my previous post, Javascript (JQuery): Social networking feeds all in one place, Facebook went and added authentication to the feed retrieval. After much head-scratching, this is how to enable the Facebook feed under the new OAuth system.

You need an access token to get to the data, so what we are going to do is create a Facebook App which the user then permits to access their information and that will give us the token we need.

So first you need to create a Facebook App. This is simpler than it sounds, we don’t need to create an App that actually does anything or even exists, we just need it for authentication. So, install the Developer App on Facebook and then go to that App and select Set Up New App. Enter the details of the App and be sure to give it a URL and domain – e.g. http://www.cheesefather.com as URL and cheesefather.com as domain. What you put it doesn’t matter that much.

The new App will have an Application id – a load of numbers. Now, this is the method to get the access token. Log in as the user you want the feed for (I am assuming you are using this to retrieve your own feed) and then go to the page:

https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=http://www.YOUR_URL.com&scope=read_stream,offline_access

Replace your App id and URL in the example. What we are doing here is creating an App request to the user to access data, including the feed (read_stream) and to access the data when they are offline (offline_access) with a token that does not expire (ever, if I’m reading the docs correctly, even if they uninstall the App).

Once you have accepted, the script continues to your URL, passing a very long code to it (you can just copy it from the address bar) – copy this code, the part after ?code=

Then we can finally request the access token. As well as the two codes we just used we also need your App Secret from your Facebook App page. Get the secret and then go to the following page:

https://graph.facebook.com/oauth/access_token?client_id=YOUR_APP_ID&redirect_uri=http://www.YOUR_URL.com&client_secret=YOUR_APP_SECRET&code=THAT_LONG_CODE&type=client_cred

Obviously replace your App id, URL, App secret and the long code with your variables. The script passes back to you an access token (check the source code if your browser isn’t displaying it).

All you need to do now is add that access token to the feed request (see the previous post for the rest of the scripts):

$.getJSON(" https://graph.facebook.com/USER_ID/posts?access_token=ACCESS_TOKEN&limit=5&callback=?",

…replacing the user id of the feed to want to retrieve.

BUT WAIT!…

You don’t want people who check your source code to have access to your Facebook account, so we need to hide that token. This is how I did it – call a PHP proxy script from the Javascript and the PHP return the content minus the access token. So you change that line to:

$.getJSON("facebook.inc.php?callback=?",

Or whatever the name of your new PHP file is. And then the contents of that new file are:

<?php
$access_token = 'YOUR_ACCESS_TOKEN';
header('Content-Type: text/javascript; charset=UTF-8');
ini_set('user_agent', $_SERVER['HTTP_USER_AGENT']);
$handle = fopen('https://graph.facebook.com/USER_ID/posts?access_token='.$access_token.'&limit=5&callback='.$_GET['callback'], 'rb');
$contents = '';
if ($handle) {
while (!feof($handle)) {
$contents .= fread($handle, 8192);
}
}
fclose($handle);
$contents = str_replace($access_token,'',$contents);
print_r($contents);
exit();
?>

Replace your access token and user id in the above example.

What this code is doing is as follows: you define your access token, you tell the browser that it’s outputting Javascript (so that JQuery interprets the results properly), you spoof some browser information so that Facebook returns the data correctly, then you open a connection to the JSON page using your access token and the reference that JQuery has assigned the JSON, then we remove all references to your access token from the output (it appears in links that are returned) and finally print the output so that it can be interpreted by the original JQuery function. Voila! What was so simple just a week ago is now quite a bit more complicated…

Javascript (JQuery): Social networking feeds all in one place

Today we are going to get feeds from Twitter, Facebook, Youtube and Flickr all in one place for your website using JSON and the JQuery library:

Be careful on this page with wrapped lines!

Firstly we declare the jquery library in our head section (obviously download it first and change the path to match your system:

<script src="lib/jquery-1.4.2.min.js"></script>

Now we define a div to put all the feeds in:

<div id="l_tweets"><br /><br />Social Networks Update:</div>

Now let’s write some Javascript! We’ll start with Twitter:

<script type="text/javascript">
//twitter - use your own username in the getJSON line
//we'll get the feed and work out how many days ago the content was posted
$.getJSON("http://twitter.com/statuses/user_timeline.json?screen_name=username&include_entities=true&count=5&callback=?",
function(data){
$.each(data, function(i,item){
dp = item.created_at.split(" ");
cr = Date.parse(dp[1]+' '+dp[2]+' '+dp[5]);
tm = (new Date()).getTime();
dy = (tm - cr) / 86400000;
ct = item.text;
ct = ct.replace(/http:\/\/\S+/g,'<a href="$&" target="_blank">$&</a>'); //make urls into links, do the same for hashtags etc:
ct = ct.replace(/\s(@)(\w+)/g,' @<a onclick="javascript:pageTracker._trackPageview(\'/outgoing/twitter.com/\');" href="http://twitter.com/$2" target="_blank">$2</a>');
ct = ct.replace(/\s(#)(\w+)/g,' #<a onclick="javascript:pageTracker._trackPageview(\'/outgoing/search.twitter.com/search?q=%23\');" href="http://search.twitter.com/search?q=%23$2" target="_blank">$2</a>');
//add the feed to the div
$("#l_tweets").append('<div> '+ct+'<br />'+Math.round(dy)+' days ago</div><br />');
}); //each
} //function
); //json

Note that the # and @ replace lines may wrap here, but they should be on one line.

[EDIT – this no longer works for Facebook since they change their authentication methods, please see my new post to get the Facebook feed]

Let’s do the same thing for Facebook now – getting the date into a format that Javascript understands is a little more complicated this time:

//facebook - again use your own username
$.getJSON("http://graph.facebook.com/username/posts?limit=5&callback=?",
function(json){
$.each(json.data, function(i,fb){
if (fb.type=='video' || fb.type=='link') {
if (fb.link) fb.message = '<a href="' + fb.link + '" target="_blank">' + fb.name + '</a>';
else fb.message = '<a href="' + fb.source + '" target="_blank">' + fb.name + '</a>';
}
else fb.message = fb.message.replace(/http:\/\/\S+/g,'<a href="$&" target="_blank">$&</a>');
var d=new Date();
dt1 = fb.created_time.split("T");
dt2 = dt1[0].split("-");
d.setDate(dt2[2]);
d.setFullYear(dt2[0]);
d.setMonth(dt2[1]-1);
cr = Date.parse(d);
tm = (new Date()).getTime();
dy = (tm - cr) / 86400000;
$("#l_tweets").append('<div>' + '' + fb.message + '' + '<br />(' + Math.round(dy) + ' days ago)</div><br />');
}); //each
} //function
); //json

The quotes either side of the fb.message counteract an Internet Explorer problem where content appears as undefined. Now on to Youtube, this is quite similar, but we are throwing images into the mix:

//youtube - as ever, replace your username
$.getJSON('http://gdata.youtube.com/feeds/users/username/uploads?alt=json-in-script&max-results=5&callback=?',
function(data) {
$.each(data.feed.entry, function(i, item) {
var published = item['published']['$t'];
var url = item['media$group']['media$content'][0]['url'];
var media_title = item['media$group']['media$title']['$t'];
var media_descr = item['media$group']['media$description']['$t'];
var thumb = item['media$group']['media$thumbnail'][0]['url'];
var d=new Date();
dt1 = published.split("T");
dt2 = dt1[0].split("-");
d.setDate(dt2[2]);
d.setFullYear(dt2[0]);
d.setMonth(dt2[1]-1);
cr = Date.parse(d);
tm = (new Date()).getTime();
dy = (tm - cr) / 86400000;
//note this next part is all one line
$("#l_tweets").append('<div><a href="' + url + '"><img src="' + thumb + '" width="64" height="36"><br />' + media_title + ' (' + media_descr + ')</a><br />(' + Math.round(dy) + ' days ago)</div><br />');
}); //each
} //function
); //json

Just one more to go – Flickr. A couple of things to note here. Firstly, your user id in the JSON link is not your username, you can map your username to the id here: http://idgettr.com. Secondly, all the other feeds have have a method of limiting results (I have chosen 5 results each so far). For this feed, we must create our own limiter.

//flickr - see the nore above about your user id
var i = 0;
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?id=user_id&lang=en-us&format=json&jsoncallback=?",
function(data){
$.each(data.items, function(i,item){
if (i<5) {
var d=new Date();
dt1 = item.published.split("T");
dt2 = dt1[0].split("-");
d.setDate(dt2[2]);
d.setFullYear(dt2[0]);
d.setMonth(dt2[1]-1);
cr = Date.parse(d);
tm = (new Date()).getTime();
dy = (tm - cr) / 86400000;
//this is all one line again
$("#l_tweets").append('<div><a href="' + item.link + '"><img src="' + item.media.m + '" width="64" height="36"><br />' + item.title + '</a><br />(' + Math.round(dy) + ' days ago)</div><br />');
i++;
} //i
}); //each
} //function
); //json

In the websites I have implemented this on, I haven’t needed to return the feeds in date order (currently they are in order of social network). To order them, this is what I would do:
1) create an array to hold the feeds
2) instead of appending the feeds to the div, add them to the array with days first, then a delimiter, then the feed
(e.g. socnet_updates.push(Math.round(dy)+’_DELIMITER_<div>’+ct+'<br />’+Math.round(dy)+’ days ago</div><br />’);)
3) after the scripts have run, wait a couple of seconds for the data to be filled out (use setTimeout counting the number of feeds returned until you have them all) and the order the array by date (use a natural order algorithm)
4) finally, iterate through the array, split the strings by your delimiter and append the second part to the div

If anyone wants me to show you that code, let me know.

Matrox RT.X100 project in Adobe Premiere RT.X2

If you open an old Matrox RT.X100 project using an RT.X2 installation, it opens as a standard Adobe Premiere project – without using any hardware acceleration, thus losing the entire point of the system. The answer is simple, but not documented anywhere:

Step 1: Create a new Matrox-based Project as normal

Step 2: Got to File, Import and import the old project (select Entire Project)
Now we have the project, but it still isn’t using the hardware or showing on the preview monitor

Step 3: Open old project sequence(s), select all and copy

Step 4: Open/create new sequence and paste the old sequence to the new sequence
Now the old project is using the new settings – simples!