Skip to content

Instantly share code, notes, and snippets.

@Synchro
Created September 8, 2011 21:48
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save Synchro/1204853 to your computer and use it in GitHub Desktop.
Save Synchro/1204853 to your computer and use it in GitHub Desktop.
PHP interface class for the Premailer API
<?php
/**
* Premailer API PHP class
* Premailer is a library/service for making HTML more palatable for various inept email clients, in particular GMail
* Primary function is to convert style tags into equivalent inline styles so styling can survive <head> tag removal
* Premailer is owned by Dialect Communications group
* @link http://premailer.dialect.ca/api
* @author Marcus Bointon <marcus@synchromedia.co.uk>
*/
class Premailer {
/**
* The Premailer API URL
*/
const ENDPOINT = 'http://premailer.dialect.ca/api/0.1/documents';
/**
* Central static method for submitting either an HTML string or a URL, optionally retrieving converted versions
* @static
* @throws Exception
* @param string $html Raw HTML source
* @param string $url URL of the source file
* @param bool $fetchresult Whether to also fetch the converted output
* @param string $adaptor Which document handler to use (hpricot (default) or nokigiri)
* @param string $base_url Base URL for converting relative links
* @param int $line_length Length of lines in the plain text version (default 65)
* @param string $link_query_string Query string appended to links
* @param bool $preserve_styles Whether to preserve any link rel=stylesheet and style elements
* @param bool $remove_ids Remove IDs from the HTML document?
* @param bool $remove_classes Remove classes from the HTML document?
* @param bool $remove_comments Remove comments from the HTML document?
* @return array Either a single strclass object containing the decoded JSON response, or a 3-element array containing result, html and plain parts if $fetchresult is set
*/
protected static function convert($html = '', $url = '', $fetchresult = true, $adaptor = 'hpricot', $base_url = '', $line_length = 65, $link_query_string = '', $preserve_styles = true, $remove_ids = false, $remove_classes = false, $remove_comments = false) {
$params = array();
if (!empty($html)) {
$params['html'] = $html;
} elseif (!empty($url)) {
$params['url'] = $url;
} else {
throw new Exception('Must supply an html or url value');
}
if ($adaptor == 'hpricot' or $adaptor == 'nokigiri') {
$params['adaptor'] = $adaptor;
}
if (!empty($base_url)) {
$params['base_url'] = $base_url;
}
$params['line_length'] = (integer)$line_length;
if (!empty($link_query_string)) {
$params['link_query_string'] = $link_query_string;
}
$params['preserve_styles'] = ($preserve_styles?'true':'false');
$params['remove_ids'] = ($remove_ids?'true':'false');
$params['remove_classes'] = ($remove_classes?'true':'false');
$params['remove_comments'] = ($remove_comments?'true':'false');
$options = array(
'timeout' => 15,
'connecttimeout' => 15,
'useragent' => 'PHP Premailer',
'ssl' => array('verifypeer' => false, 'verifyhost' => false)
);
$h = new HttpRequest(self::ENDPOINT, HttpRequest::METH_POST, $options);
$h->addPostFields($params);
try {
$response = $h->send();
$result = json_decode($response->getBody());
$code = $response->getResponseCode();
if ($code != 201) {
switch ($code) {
case 400:
throw new Exception('Content missing', 400);
break;
case 403:
throw new Exception('Access forbidden', 403);
break;
case 500:
default:
throw new Exception('Error', $code);
}
}
$return = array('result' => $result);
if ($fetchresult) {
//Get HTML and plain versions in parallel
http_persistent_handles_clean();
$pool = new HttpRequestPool;
$pool->attach(new HttpRequest($result->documents->html, HttpRequest::METH_GET, $options));
$pool->attach(new HttpRequest($result->documents->txt, HttpRequest::METH_GET, $options));
$pool->send();
foreach($pool as $request) {
if ($request->getUrl() == $result->documents->html) {
$return['html'] = $request->getResponseBody();
} elseif ($request->getUrl() == $result->documents->txt) {
$return['plain'] = $request->getResponseBody();
}
}
return $return;
}
return $result;
} catch (HttpException $e) {
var_dump($h, $e->getMessage());
return false;
}
}
/**
* Central static method for submitting either an HTML string or a URL, optionally retrieving converted versions
* @static
* @throws Exception
* @param string $html Raw HTML source
* @param bool $fetchresult Whether to also fetch the converted output
* @param string $adaptor Which document handler to use (hpricot (default) or nokigiri)
* @param string $base_url Base URL for converting relative links
* @param int $line_length Length of lines in the plain text version (default 65)
* @param string $link_query_string Query string appended to links
* @param bool $preserve_styles Whether to preserve any link rel=stylesheet and style elements
* @param bool $remove_ids Remove IDs from the HTML document?
* @param bool $remove_classes Remove classes from the HTML document?
* @param bool $remove_comments Remove comments from the HTML document?
* @return array Either a single element array containing the 'result' object, or three elements containing result, html and plain if $fetchresult is set
*/
public static function html($html, $fetchresult = true, $adaptor = 'hpricot', $base_url = '', $line_length = 65, $link_query_string = '', $preserve_styles = true, $remove_ids = false, $remove_classes = false, $remove_comments = false) {
return self::convert($html, '', $fetchresult, $adaptor, $base_url, $line_length, $link_query_string, $preserve_styles, $remove_ids, $remove_classes, $remove_comments);
}
/**
* Central static method for submitting either an HTML string or a URL, optionally retrieving converted versions
* @static
* @throws Exception
* @param string $url URL of the source file
* @param bool $fetchresult Whether to also fetch the converted output
* @param string $adaptor Which document handler to use (hpricot (default) or nokigiri)
* @param string $base_url Base URL for converting relative links
* @param int $line_length Length of lines in the plain text version (default 65)
* @param string $link_query_string Query string appended to links
* @param bool $preserve_styles Whether to preserve any link rel=stylesheet and style elements
* @param bool $remove_ids Remove IDs from the HTML document?
* @param bool $remove_classes Remove classes from the HTML document?
* @param bool $remove_comments Remove comments from the HTML document?
* @return array Either a single element array containing the 'result' object, or three elements containing result, html and plain if $fetchresult is set
*/
public static function url($url, $fetchresult = true, $adaptor = 'hpricot', $base_url = '', $line_length = 65, $link_query_string = '', $preserve_styles = true, $remove_ids = false, $remove_classes = false, $remove_comments = false) {
return self::convert('', $url, $fetchresult, $adaptor, $base_url, $line_length, $link_query_string, $preserve_styles, $remove_ids, $remove_classes, $remove_comments);
}
}
/*
Simplest usage:
$pre = Premailer::html($var_with_some_html_in);
$html = $pre['html'];
$plain = $pre['plain'];
//Similarly for URLs:
$pre = Premailer::url($url);
*/
?>
@barockok
Copy link

barockok commented Jan 6, 2012

i got this
"Fatal error: Class 'HttpRequest' not found in...."

@Synchro
Copy link
Author

Synchro commented Jan 6, 2012

You need to install/enable the PHP HTTP extension.

@hperrin
Copy link

hperrin commented Jun 26, 2012

Could you rewrite it using curl?

@hperrin
Copy link

hperrin commented Jun 26, 2012

Never mind. Looks like there's already one. https://gist.github.com/1591053

@marcovtwout
Copy link

Bugs in Line 55 + 56: remove $ from array keys

@Synchro
Copy link
Author

Synchro commented Jul 25, 2012

Thanks, fixed

@withremote
Copy link

I keep getting 500 error responses from using this api, any idea if that would be on my side or theirs?

@onassar
Copy link

onassar commented Aug 19, 2013

Hoping it's relevant: I created a PHP proxy/wrapper for the ruby library. It can be viewed here: https://github.com/onassar/PHP-Premailer

@tommytompkins
Copy link

Is this API still being maintained? Everything was working fine in my app for years and now I'm getting a 404 error when trying to connect to the endpoint http://premailer.dialect.ca/api/0.1/documents. Is there a new endpoint I should be using?

@Synchro
Copy link
Author

Synchro commented Jan 5, 2020

I don't have anything to do with the hosting of that service; It wouldn't surprise me if it's stopped working as this is many years old. I would recommend switching to a local solution like emogrifier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment