· 8 years ago · Dec 26, 2017, 10:30 PM
1<?php
2
3/**
4 * Replace '\n' with "\n". The escape sequence is not recognized when you use '.
5 * For the question of how to write line endings, see the note here.
6 * Basically, different operating systems have different conventions for line endings.
7 * Windows uses "\r\n", unix based operating systems use "\n".
8 * You should stick to one convention (I'd chose "\n") and open your file in binary mode (fopen should get "wb", not "w").
9 */
10
11/**
12 * DKIMHelper
13 * Used to create keys (using opendkim-keygen) and add entries to KeyTable and SigningTable
14 */
15
16class DKIMHelper {
17
18 //Selector for DKIM record
19 public $selector;
20 //Domain name for DKIM record ex. domain.com
21 public $domain;
22
23 //Path to DKIM Base Directory
24 public static $OPENDKIM_BASE_DIRECTORY = "G://opt//opendkim//";
25 //Name of Keytable
26 public static $OPENDKIM_KEY_TABLE = "KeyTable";
27 //Name of SigningTable
28 public static $OPENDKIM_SIGNING_TABLE = "SigningTable";
29 //Name of keys directory for storing folders and private key for use with DKIM
30 public static $OPENDKIM_KEY_DIRECTORY = "keys";
31
32 public function __construct($selector, $domain) {
33 $this->selector = $selector;
34 $this->domain = $domain;
35 echo "Creating Folder structure\n";
36 $this->_createDKIMKeyFolder();
37 echo "Adding Key Table Entry\n";
38 $this->_addKeyTableEntry();
39 echo "Adding Signing Table Entry\n";
40 $this->_addSigningTableEntry();
41 // echo $this->getDKIMValue();
42 // $this->enableDKIM();
43 // $this->disableDKIM();
44 // $this->removeDKIM();
45 }
46
47 private function _isValidDomain() {
48
49 }
50
51 /**
52 * getDKIMValue - returns the contents of keys/example.com/selector.txt contents(which is the actual DKIM record value.)
53 */
54 public function getDKIMValue() {
55 $filePath = $this->_getKeyFolderPath()."//".$this->selector.".txt";
56 $contents = file_get_contents($filePath);
57 // echo $contents;
58 return $contents;
59 }
60
61 /**
62 * _addKeyTableEntry - add a DKIM Key Table Entry to KeyTable file if none exists.
63 *
64 */
65 //key table entry format : mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private
66 private function _addKeyTableEntry() {
67 $keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "a+");
68 // print_r(stream_get_meta_data($keyTableFile));
69 while(!feof($keyTableFile)) {
70 $line = fgets($keyTableFile);
71 $offset = strpos($line, $this->_getKeyTableEntryRecord());
72 if($offset !== FALSE) {
73 //found the key
74 //do nothing if key found.
75 break;
76 }
77 }
78 if($offset === FALSE) {
79 //lets add it
80 //move to end
81 fseek($keyTableFile, 0, SEEK_END);
82 flock($keyTableFile, LOCK_EX);
83 fwrite($keyTableFile, "\n");
84 //add metadata if necessary.
85 //append data
86 fputs($keyTableFile, $this->_getKeyTableEntryRecord());
87 fwrite($keyTableFile, "\n");
88 flock($keyTableFile, LOCK_UN);
89 //close
90 }
91
92 fclose($keyTableFile);
93 }
94
95 public function enableDKIM() {
96 //enable DKIM Records?
97 $this->_enableDKIMKeyTableFile();
98 $this->_enableDKIMSigningTableFile();
99 }
100
101 public function disableDKIM() {
102 $this->_disableDKIMKeyTableFile();
103 $this->_disableDKIMSigningTableFile();
104 }
105
106 private function _enableDKIMKeyTableFile() {
107 $keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "c+");
108 // print_r(stream_get_meta_data($keyTableFile));
109 while(!feof($keyTableFile)) {
110 $line = fgets($keyTableFile);
111 $offset = strpos($line, $this->_getKeyTableEntryRecord());
112 if($offset !== FALSE) {
113 //found the key
114 //do nothing if key found.
115 break;
116 }
117 }
118 $cursorPosition = ftell($keyTableFile);
119 //move cursor position to starrt of line
120 $cursorPosition = $cursorPosition - strlen($line);
121 fseek($keyTableFile, $cursorPosition, SEEK_SET);
122 $disabledOffset = strpos($line, "#");
123 // echo fread($keyTableFile, 15);
124 //if disabledOffset = FALSE then item is not disabled
125 if($disabledOffset === FALSE) {
126 // do nothing
127 echo "Already Enabled\n";
128 } else {
129 echo "Writing data to file \n";
130 //get a lock on file before editing
131 $lineLength = strlen($line);
132 $line = preg_replace("/./", " ", $line);
133 //fwrite and flock are used since this file can be accessed by multiple processes at once
134 //updation by other process should not result in our changes being lost so we get a exclusive write to it.
135 flock($keyTableFile, LOCK_EX);
136 fwrite($keyTableFile, $line, $lineLength);
137 fseek($keyTableFile, $cursorPosition, SEEK_SET);
138 fwrite($keyTableFile, $this->_getKeyTableEntryRecord());
139 flock($keyTableFile, LOCK_UN);
140
141 }
142 fclose($keyTableFile);
143 }
144
145 private function _disableDKIMKeyTableFile() {
146 //disable DKIM records.
147 $keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "c+");
148 // print_r(stream_get_meta_data($keyTableFile));
149 while(!feof($keyTableFile)) {
150 $line = fgets($keyTableFile);
151 $offset = strpos($line, $this->_getKeyTableEntryRecord());
152 if($offset !== FALSE) {
153 //found the key
154 //do nothing if key found.
155 break;
156 }
157 }
158 $cursorPosition = ftell($keyTableFile);
159 //move cursor position to starrt of line
160 $cursorPosition = $cursorPosition - strlen($line);
161 fseek($keyTableFile, $cursorPosition, SEEK_SET);
162 $disabledOffset = strpos($line, "#");
163 // echo fread($keyTableFile, 15);
164 //if disabledOffset = FALSE then item is not disabled
165 if($disabledOffset === FALSE) {
166 // do nothing
167 //get a lock on file before editing
168 $lineLength = strlen($line);
169 $line = preg_replace("/./", " ", $line);
170 //fwrite and flock are used since this file can be accessed by multiple processes at once
171 //updation by other process should not result in our changes being lost so we get a exclusive write to it.
172 flock($keyTableFile, LOCK_EX);
173 fwrite($keyTableFile, $line, $lineLength);
174 fseek($keyTableFile, $cursorPosition, SEEK_SET);
175 fwrite($keyTableFile, '#'.$this->_getKeyTableEntryRecord());
176 flock($keyTableFile, LOCK_UN);
177 } else {
178
179 }
180 fclose($keyTableFile);
181 }
182
183 private function _getKeyTableEntryRecord() {
184 return $this->selector."._domainkey.".$this->domain." ".$this->domain.":".$this->selector.":".$this->_getKeyFolderPath()."/".$this->selector.".private";
185 }
186
187 private function _addSigningTableEntry() {
188 $signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "a+");
189 while(!feof($signingTableFile)) {
190 $line = fgets($signingTableFile);
191 $offset = strpos($line, $this->_getSigningTableEntryRecord());
192 if($offset !== FALSE) {
193 //found the key
194 //do nothing if key found.
195 break;
196 }
197 }
198 if($offset === FALSE) {
199 //lets add it
200 //move to end
201 fseek($signingTableFile, 0, SEEK_END);
202 flock($signingTableFile, LOCK_EX);
203 fwrite($signingTableFile, "\n");
204 //append data
205 fputs($signingTableFile, $this->_getSigningTableEntryRecord());
206 fwrite($signingTableFile, "\n");
207 flock($signingTableFile, LOCK_UN);
208 //close
209 }
210
211 fclose($signingTableFile);
212 }
213
214 private function _enableDKIMSigningTableFile() {
215 $signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "c+");
216 // print_r(stream_get_meta_data($signingTableFile));
217 while(!feof($signingTableFile)) {
218 $line = fgets($signingTableFile);
219 $offset = strpos($line, $this->_getSigningTableEntryRecord());
220 if($offset !== FALSE) {
221 //found the key
222 //do nothing if key found.
223 break;
224 }
225 }
226 $cursorPosition = ftell($signingTableFile);
227 //move cursor position to starrt of line
228 $cursorPosition = $cursorPosition - strlen($line);
229 fseek($signingTableFile, $cursorPosition, SEEK_SET);
230 $disabledOffset = strpos($line, "#");
231 // echo fread($signingTableFile, 15);
232 //if disabledOffset = FALSE then item is not disabled
233 if($disabledOffset === FALSE) {
234 // do nothing
235 echo "Already Enabled\n";
236 } else {
237 echo "Writing data to file \n";
238 //get a lock on file before editing
239 $lineLength = strlen($line);
240 $line = preg_replace("/./", " ", $line);
241 //fwrite and flock are used since this file can be accessed by multiple processes at once
242 //updation by other process should not result in our changes being lost so we get a exclusive write to it.
243 flock($signingTableFile, LOCK_EX);
244 fwrite($signingTableFile, $line, $lineLength);
245 fseek($signingTableFile, $cursorPosition, SEEK_SET);
246 fwrite($signingTableFile, $this->_getSigningTableEntryRecord());
247 flock($signingTableFile, LOCK_UN);
248
249 }
250 fclose($signingTableFile);
251 }
252
253 private function _disableDKIMSigningTableFile() {
254 //disable DKIM records.
255 $signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "c+");
256 // print_r(stream_get_meta_data($signingTableFile));
257 while(!feof($signingTableFile)) {
258 $line = fgets($signingTableFile);
259 $offset = strpos($line, $this->_getSigningTableEntryRecord());
260 if($offset !== FALSE) {
261 //found the key
262 //do nothing if key found.
263 break;
264 }
265 }
266 $cursorPosition = ftell($signingTableFile);
267 //move cursor position to starrt of line
268 $cursorPosition = $cursorPosition - strlen($line);
269 fseek($signingTableFile, $cursorPosition, SEEK_SET);
270 $disabledOffset = strpos($line, "#");
271 // echo fread($signingTableFile, 15);
272 //if disabledOffset = FALSE then item is not disabled
273 if($disabledOffset === FALSE) {
274 // do nothing
275 //get a lock on file before editing
276 $lineLength = strlen($line);
277 $line = preg_replace("/./", " ", $line);
278 //fwrite and flock are used since this file can be accessed by multiple processes at once
279 //updation by other process should not result in our changes being lost so we get a exclusive write to it.
280 flock($signingTableFile, LOCK_EX);
281 fwrite($signingTableFile, $line, $lineLength);
282 fseek($signingTableFile, $cursorPosition, SEEK_SET);
283 fwrite($signingTableFile, '#'.$this->_getSigningTableEntryRecord());
284 flock($signingTableFile, LOCK_UN);
285 } else {
286
287 }
288 fclose($signingTableFile);
289 }
290
291 //Signing tablle entry format *@example.com mail._domainkey.example.com
292 private function _getSigningTableEntryRecord() {
293 return "*@".$this->domain." ".$this->selector."._domainkey.".$this->domain;
294 }
295
296 /**
297 * _createDKIMKeyFolder - create key folder if none exists
298 * a folder inside /opt/opendkim/keys/ is created with the same name as that of $this->domain
299 * /opt/opendkim/keys/google.com
300 * Private key and DKIM TXT record is generated if none exists.
301 */
302 private function _createDKIMKeyFolder() {
303
304 if(file_exists($this->_getKeyFolderPath())) {
305 //if folder exists make see if file is present
306 if(file_exists($this->_getKeyFolderPath()."//".$this->selector.".txt") && file_exists($this->_getKeyFolderPath()."//".$this->selector.".private")) {
307 //if keyfile and dkim exists.
308 //do nothing.
309 } else {
310 echo $this->_generateDKIMKeys();
311 }
312
313 } else {
314 //create folder
315 if(mkdir($this->_getKeyFolderPath())) {
316 //directory created.
317 echo "Directory Created";
318 echo $this->_generateDKIMKeys();
319 } else {
320 //stop
321 die();
322 }
323 }
324 }
325
326 private function _generateDKIMKeys() {
327 return shell_exec("cd ".$this->_getKeyFolderPath()."//".$this->domain." && opendkim-keygen -s ".$this->selector." -d ".$this->domain);
328 }
329
330 private function _getKeyFolderPath() {
331 return self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_DIRECTORY."//".$this->domain;
332 }
333
334 public function removeDKIM() {
335 //delete keys
336 $output = shell_exec("rm -rf ".$this->_getKeyFolderPath()."//".$this->domain);
337 //remove entries from KeyTable and SigningTable.
338 $this->_removeKeyTablEntry();
339 $this->_removeSigningTableEntry();
340
341 }
342
343 private function _removeKeyTablEntry() {
344 $keyTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_KEY_TABLE, "c+");
345 // print_r(stream_get_meta_data($keyTableFile));
346 while(!feof($keyTableFile)) {
347 $line = fgets($keyTableFile);
348 $offset = strpos($line, $this->_getKeyTableEntryRecord());
349 if($offset !== FALSE) {
350 //found the key
351 //do nothing if key found.
352 break;
353 }
354 }
355 $cursorPosition = ftell($keyTableFile);
356 //move cursor position to starrt of line
357 $cursorPosition = $cursorPosition - strlen($line);
358 fseek($keyTableFile, $cursorPosition, SEEK_SET);
359 if($offset === FALSE) {
360 // do nothing
361 echo "Non Existent\n";
362 } else {
363
364 //get a lock on file before editing
365 $lineLength = strlen($line);
366 $line = preg_replace("/./", " ", $line);
367 //fwrite and flock are used since this file can be accessed by multiple processes at once
368 //updation by other process should not result in our changes being lost so we get a exclusive write to it.
369 flock($keyTableFile, LOCK_EX);
370 fwrite($keyTableFile, $line, $lineLength);
371 flock($keyTableFile, LOCK_UN);
372
373 }
374 fclose($keyTableFile);
375 }
376
377 private function _removeSigningTableEntry() {
378 $signingTableFile = fopen(self::$OPENDKIM_BASE_DIRECTORY.self::$OPENDKIM_SIGNING_TABLE, "c+");
379 // print_r(stream_get_meta_data($signingTableFile));
380 while(!feof($signingTableFile)) {
381 $line = fgets($signingTableFile);
382 $offset = strpos($line, $this->_getSigningTableEntryRecord());
383 if($offset !== FALSE) {
384 //found the key
385 //do nothing if key found.
386 break;
387 }
388 }
389 $cursorPosition = ftell($signingTableFile);
390 //move cursor position to starrt of line
391 $cursorPosition = $cursorPosition - strlen($line);
392 fseek($signingTableFile, $cursorPosition, SEEK_SET);
393 if($offset === FALSE) {
394 // do nothing
395 echo "Non Existent\n";
396 } else {
397 //get a lock on file before editing
398 $lineLength = strlen($line);
399 $line = preg_replace("/./", " ", $line);
400 //fwrite and flock are used since this file can be accessed by multiple processes at once
401 //updation by other process should not result in our changes being lost so we get a exclusive write to it.
402 flock($signingTableFile, LOCK_EX);
403 fwrite($signingTableFile, $line, $lineLength);
404 flock($signingTableFile, LOCK_UN);
405
406 }
407 fclose($signingTableFile);
408 }
409}