Skip to content

Instantly share code, notes, and snippets.

@pareshchouhan
Created December 22, 2017 06:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pareshchouhan/ceecb5fc97e6f6d2b8f8a4001b975ce4 to your computer and use it in GitHub Desktop.
Save pareshchouhan/ceecb5fc97e6f6d2b8f8a4001b975ce4 to your computer and use it in GitHub Desktop.
<?php
/**
* Replace '\n' with "\n". The escape sequence is not recognized when you use '.
* For the question of how to write line endings, see the note here.
* Basically, different operating systems have different conventions for line endings.
* Windows uses "\r\n", unix based operating systems use "\n".
* You should stick to one convention (I'd chose "\n") and open your file in binary mode (fopen should get "wb", not "w").
*/
/**
* DKIMHelper
* Used to create keys (using opendkim-keygen) and add entries to KeyTable and SigningTable
*/
class DKIMHelper {
//Selector for DKIM record
public $selector;
//Domain name for DKIM record ex. domain.com
public $domain;
//Path to DKIM Base Directory
public static $OPENDKIM_BASE_DIRECTORY = "G://opt//opendkim//";
//Name of Keytable
public static $OPENDKIM_KEY_TABLE = "KeyTable";
//Name of SigningTable
public static $OPENDKIM_SIGNING_TABLE = "SigningTable";
//Name of keys directory for storing folders and private key for use with DKIM
public static $OPENDKIM_KEY_DIRECTORY = "keys";
public function __construct($selector, $domain) {
$this->selector = $selector;
$this->domain = $domain;
echo "Creating Folder structure\n";
$this->_createDKIMKeyFolder();
echo "Adding Key Table Entry\n";
$this->_addKeyTableEntry();
echo "Adding Signing Table Entry\n";
$this->_addSigningTableEntry();
// echo $this->getDKIMValue();
// $this->enableDKIM();
// $this->disableDKIM();
// $this->removeDKIM();
}
private function _isValidDomain() {
}
/**
* getDKIMValue - returns the contents of keys/example.com/selector.txt contents(which is the actual DKIM record value.)
*/
public function getDKIMValue() {
$filePath = $this->_getKeyFolderPath()."//".$this->selector.".txt";
$contents = file_get_contents($filePath);
// echo $contents;
return $contents;
}
/**
* _addKeyTableEntry - add a DKIM Key Table Entry to KeyTable file if none exists.
*
*/
//key table entry format : mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private
private function _addKeyTableEntry() {
$keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "a+");
// print_r(stream_get_meta_data($keyTableFile));
while(!feof($keyTableFile)) {
$line = fgets($keyTableFile);
$offset = strpos($line, $this->_getKeyTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
if($offset === FALSE) {
//lets add it
//move to end
fseek($keyTableFile, 0, SEEK_END);
flock($keyTableFile, LOCK_EX);
fwrite($keyTableFile, "\n");
//add metadata if necessary.
//append data
fputs($keyTableFile, $this->_getKeyTableEntryRecord());
fwrite($keyTableFile, "\n");
flock($keyTableFile, LOCK_UN);
//close
}
fclose($keyTableFile);
}
public function enableDKIM() {
//enable DKIM Records?
$this->_enableDKIMKeyTableFile();
$this->_enableDKIMSigningTableFile();
}
public function disableDKIM() {
$this->_disableDKIMKeyTableFile();
$this->_disableDKIMSigningTableFile();
}
private function _enableDKIMKeyTableFile() {
$keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "c+");
// print_r(stream_get_meta_data($keyTableFile));
while(!feof($keyTableFile)) {
$line = fgets($keyTableFile);
$offset = strpos($line, $this->_getKeyTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
$cursorPosition = ftell($keyTableFile);
//move cursor position to starrt of line
$cursorPosition = $cursorPosition - strlen($line);
fseek($keyTableFile, $cursorPosition, SEEK_SET);
$disabledOffset = strpos($line, "#");
// echo fread($keyTableFile, 15);
//if disabledOffset = FALSE then item is not disabled
if($disabledOffset === FALSE) {
// do nothing
echo "Already Enabled\n";
} else {
echo "Writing data to file \n";
//get a lock on file before editing
$lineLength = strlen($line);
$line = preg_replace("/./", " ", $line);
//fwrite and flock are used since this file can be accessed by multiple processes at once
//updation by other process should not result in our changes being lost so we get a exclusive write to it.
flock($keyTableFile, LOCK_EX);
fwrite($keyTableFile, $line, $lineLength);
fseek($keyTableFile, $cursorPosition, SEEK_SET);
fwrite($keyTableFile, $this->_getKeyTableEntryRecord());
flock($keyTableFile, LOCK_UN);
}
fclose($keyTableFile);
}
private function _disableDKIMKeyTableFile() {
//disable DKIM records.
$keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "c+");
// print_r(stream_get_meta_data($keyTableFile));
while(!feof($keyTableFile)) {
$line = fgets($keyTableFile);
$offset = strpos($line, $this->_getKeyTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
$cursorPosition = ftell($keyTableFile);
//move cursor position to starrt of line
$cursorPosition = $cursorPosition - strlen($line);
fseek($keyTableFile, $cursorPosition, SEEK_SET);
$disabledOffset = strpos($line, "#");
// echo fread($keyTableFile, 15);
//if disabledOffset = FALSE then item is not disabled
if($disabledOffset === FALSE) {
// do nothing
//get a lock on file before editing
$lineLength = strlen($line);
$line = preg_replace("/./", " ", $line);
//fwrite and flock are used since this file can be accessed by multiple processes at once
//updation by other process should not result in our changes being lost so we get a exclusive write to it.
flock($keyTableFile, LOCK_EX);
fwrite($keyTableFile, $line, $lineLength);
fseek($keyTableFile, $cursorPosition, SEEK_SET);
fwrite($keyTableFile, '#'.$this->_getKeyTableEntryRecord());
flock($keyTableFile, LOCK_UN);
} else {
}
fclose($keyTableFile);
}
private function _getKeyTableEntryRecord() {
return $this->selector."._domainkey.".$this->domain." ".$this->domain.":".$this->selector.":".$this->_getKeyFolderPath()."/".$this->selector.".private";
}
private function _addSigningTableEntry() {
$signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "a+");
while(!feof($signingTableFile)) {
$line = fgets($signingTableFile);
$offset = strpos($line, $this->_getSigningTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
if($offset === FALSE) {
//lets add it
//move to end
fseek($signingTableFile, 0, SEEK_END);
flock($signingTableFile, LOCK_EX);
fwrite($signingTableFile, "\n");
//append data
fputs($signingTableFile, $this->_getSigningTableEntryRecord());
fwrite($signingTableFile, "\n");
flock($signingTableFile, LOCK_UN);
//close
}
fclose($signingTableFile);
}
private function _enableDKIMSigningTableFile() {
$signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "c+");
// print_r(stream_get_meta_data($signingTableFile));
while(!feof($signingTableFile)) {
$line = fgets($signingTableFile);
$offset = strpos($line, $this->_getSigningTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
$cursorPosition = ftell($signingTableFile);
//move cursor position to starrt of line
$cursorPosition = $cursorPosition - strlen($line);
fseek($signingTableFile, $cursorPosition, SEEK_SET);
$disabledOffset = strpos($line, "#");
// echo fread($signingTableFile, 15);
//if disabledOffset = FALSE then item is not disabled
if($disabledOffset === FALSE) {
// do nothing
echo "Already Enabled\n";
} else {
echo "Writing data to file \n";
//get a lock on file before editing
$lineLength = strlen($line);
$line = preg_replace("/./", " ", $line);
//fwrite and flock are used since this file can be accessed by multiple processes at once
//updation by other process should not result in our changes being lost so we get a exclusive write to it.
flock($signingTableFile, LOCK_EX);
fwrite($signingTableFile, $line, $lineLength);
fseek($signingTableFile, $cursorPosition, SEEK_SET);
fwrite($signingTableFile, $this->_getSigningTableEntryRecord());
flock($signingTableFile, LOCK_UN);
}
fclose($signingTableFile);
}
private function _disableDKIMSigningTableFile() {
//disable DKIM records.
$signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "c+");
// print_r(stream_get_meta_data($signingTableFile));
while(!feof($signingTableFile)) {
$line = fgets($signingTableFile);
$offset = strpos($line, $this->_getSigningTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
$cursorPosition = ftell($signingTableFile);
//move cursor position to starrt of line
$cursorPosition = $cursorPosition - strlen($line);
fseek($signingTableFile, $cursorPosition, SEEK_SET);
$disabledOffset = strpos($line, "#");
// echo fread($signingTableFile, 15);
//if disabledOffset = FALSE then item is not disabled
if($disabledOffset === FALSE) {
// do nothing
//get a lock on file before editing
$lineLength = strlen($line);
$line = preg_replace("/./", " ", $line);
//fwrite and flock are used since this file can be accessed by multiple processes at once
//updation by other process should not result in our changes being lost so we get a exclusive write to it.
flock($signingTableFile, LOCK_EX);
fwrite($signingTableFile, $line, $lineLength);
fseek($signingTableFile, $cursorPosition, SEEK_SET);
fwrite($signingTableFile, '#'.$this->_getSigningTableEntryRecord());
flock($signingTableFile, LOCK_UN);
} else {
}
fclose($signingTableFile);
}
//Signing tablle entry format *@example.com mail._domainkey.example.com
private function _getSigningTableEntryRecord() {
return "*@".$this->domain." ".$this->selector."._domainkey.".$this->domain;
}
/**
* _createDKIMKeyFolder - create key folder if none exists
* a folder inside /opt/opendkim/keys/ is created with the same name as that of $this->domain
* /opt/opendkim/keys/google.com
* Private key and DKIM TXT record is generated if none exists.
*/
private function _createDKIMKeyFolder() {
if(file_exists($this->_getKeyFolderPath())) {
//if folder exists make see if file is present
if(file_exists($this->_getKeyFolderPath()."//".$this->selector.".txt") && file_exists($this->_getKeyFolderPath()."//".$this->selector.".private")) {
//if keyfile and dkim exists.
//do nothing.
} else {
echo $this->_generateDKIMKeys();
}
} else {
//create folder
if(mkdir($this->_getKeyFolderPath())) {
//directory created.
echo "Directory Created";
echo $this->_generateDKIMKeys();
} else {
//stop
die();
}
}
}
private function _generateDKIMKeys() {
return shell_exec("cd ".$this->_getKeyFolderPath()."//".$this->domain." && opendkim-keygen -s ".$this->selector." -d ".$this->domain);
}
private function _getKeyFolderPath() {
return self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_DIRECTORY."//".$this->domain;
}
public function removeDKIM() {
//delete keys
$output = shell_exec("rm -rf ".$this->_getKeyFolderPath()."//".$this->domain);
//remove entries from KeyTable and SigningTable.
$this->_removeKeyTablEntry();
$this->_removeSigningTableEntry();
}
private function _removeKeyTablEntry() {
$keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "c+");
// print_r(stream_get_meta_data($keyTableFile));
while(!feof($keyTableFile)) {
$line = fgets($keyTableFile);
$offset = strpos($line, $this->_getKeyTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
$cursorPosition = ftell($keyTableFile);
//move cursor position to starrt of line
$cursorPosition = $cursorPosition - strlen($line);
fseek($keyTableFile, $cursorPosition, SEEK_SET);
if($offset === FALSE) {
// do nothing
echo "Non Existent\n";
} else {
//get a lock on file before editing
$lineLength = strlen($line);
$line = preg_replace("/./", " ", $line);
//fwrite and flock are used since this file can be accessed by multiple processes at once
//updation by other process should not result in our changes being lost so we get a exclusive write to it.
flock($keyTableFile, LOCK_EX);
fwrite($keyTableFile, $line, $lineLength);
flock($keyTableFile, LOCK_UN);
}
fclose($keyTableFile);
}
private function _removeSigningTableEntry() {
$signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "c+");
// print_r(stream_get_meta_data($signingTableFile));
while(!feof($signingTableFile)) {
$line = fgets($signingTableFile);
$offset = strpos($line, $this->_getSigningTableEntryRecord());
if($offset !== FALSE) {
//found the key
//do nothing if key found.
break;
}
}
$cursorPosition = ftell($signingTableFile);
//move cursor position to starrt of line
$cursorPosition = $cursorPosition - strlen($line);
fseek($signingTableFile, $cursorPosition, SEEK_SET);
if($offset === FALSE) {
// do nothing
echo "Non Existent\n";
} else {
//get a lock on file before editing
$lineLength = strlen($line);
$line = preg_replace("/./", " ", $line);
//fwrite and flock are used since this file can be accessed by multiple processes at once
//updation by other process should not result in our changes being lost so we get a exclusive write to it.
flock($signingTableFile, LOCK_EX);
fwrite($signingTableFile, $line, $lineLength);
flock($signingTableFile, LOCK_UN);
}
fclose($signingTableFile);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment