Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
PHP build script for a Google Chrome browser extension
<?php
class ChromePluginCompiler extends PluginCompiler
{
// constants - set these in your subclass
public $major_version = '5.0';
public $browser = 'chrome';
protected $output_mime_type = 'application/x-chrome-extension';
protected $output_filename = 'ChromeExtension.crx';
protected $build_dir = 'chrome';
protected $private_key = "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----";
protected $public_key = "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----";
protected $public_key_der_base64 = "...";
protected $files = array(
'manifest.json',
'icon16.png',
'icon64.png',
'icon128.png',
'_locales/en/messages.json',
'content/jquery-1.5.1.js',
'content/mtoolbar.js',
'content/content.js',
'content/signrequest.js',
'content/background.html',
);
protected $tempdir;
public function compile()
{
// create a temporary build directory
$this->tempdir = tempnam($this->_tmpdir(), 'msg');
unlink($this->tempdir);
mkdir($this->tempdir);
$dir = $this->tempdir.'/';
$key = $this->build_path;
$name = $this->build_dir;
$crx = "$name.crx";
$zip = "$name.zip";
$this->tempfile = $dir.$zip;
// data to insert into plugin files...
$version = $this->version();
$tags = array(
'content/background.html' => array(
'{{msg_secret}}' => Config::get('msg_secret'),
'{{msg_api_endpoint}}' => Config::get('msg_api_endpoint'),
'{{version}}' => $version,
'{{distributor_id}}' => $this->distributor->pk(),
),
'manifest.json' => array(
'{{version}}' => $version,
'{{msg_api_endpoint}}' => Config::get('msg_api_endpoint'),
'{{updateURL}}' => Config::get('msg_include_update_url')?
'"update_url": "'.Config::get('msg_api_endpoint')."/download/crupdate.xml?distributor_id=".$this->distributor->pk().'",' :
'',
),
);
// Chrome plugins start with a zip archive...
$z = new ZipArchiveImproved();
if ($z->open($this->tempfile, ZIPARCHIVE::CREATE) !== TRUE)
{
throw new Exception("Cannot open $this->tempfile");
}
// add each file to the archive
foreach ($this->files as $file)
{
if ($tags[$file])
{
$filecontents = str_replace(
array_keys($tags[$file]),
array_values($tags[$file]),
file_get_contents($this->build_path.$file)
);
$z->addFromString($file, $filecontents);
}
else
{
$z->addFile($this->build_path.$file, $file);
}
}
// build
$z->close();
// make a SHA1 signature using our private key
$pk = openssl_pkey_get_private($this->private_key);
openssl_sign(file_get_contents($this->tempfile), $signature, $pk, 'sha1');
openssl_free_key($pk);
// decode the public key
$key = base64_decode($this->public_key_der_base64);
// .crx package format:
//
// magic number char(4)
// crx format ver byte(4)
// pub key lenth byte(4)
// signature length byte(4)
// public key string
// signature string
// package contents, zipped string
//
// see http://code.google.com/chrome/extensions/crx.html
//
$fh = fopen($dir.$crx, 'wb');
fwrite($fh, 'Cr24'); // extension file magic number
fwrite($fh, pack('V', 2)); // crx format version
fwrite($fh, pack('V', strlen($key))); // public key length
fwrite($fh, pack('V', strlen($signature))); // signature length
fwrite($fh, $key); // public key
fwrite($fh, $signature); // signature
fwrite($fh, file_get_contents($this->tempfile)); // package contents, zipped
fclose($fh);
// clean up build files
@unlink($this->tempfile); // zip file
$this->tempfile = array_shift(explode('.', $dir)).'.crx'; // move the .crx file up one level
if (@rename($dir.$crx, $this->tempfile))
{
// delete the temporary working dir
@rmdir($dir);
}
else
{
// failsafe ('twas a nice thought!)
$this->tempfile = $dir.$crx;
}
// return the path to the compiled plugin
return $this->tempfile;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.