2e6c05f1fda8d9d29c61b0f18d75de4ed0e296dd
[openpgp-sendmail-classes.git] / emailclass.inc.php
1 <?  
2  define("GPG_SYMMETRIC" ,1);
3  define("GPG_ASSYMETRIC",2); //deprecated, spelling error, kept for backwards-compatibility
4  define("GPG_ASYMMETRIC",2);
5  
6  class sendmail_base
7  {
8   /*
9    *
10    * Created by Kristian Fiskerstrand
11    * Website: http://www.kfwebs.net
12    * The above Copyright statement shall be kept intact at all times.
13    *
14    * ***************************************************************
15    * Example of usage:
16    * <?
17    *  header("Content-type: text/plain");
18    *  require("emailclass.php");
19    *  $a = new sendmail;
20    *  $a->from("noreply@kfwebs.net");
21    *  $a->add_to("@kfwebs.net");
22    *  $a->add_cc("user1@kfwebs.net");
23    *  $a->add_bcc("user2@kfwebs.net");
24    *  $a->subject("This is the subject - blah");
25    *  $a->body("This is a test\n\n");
26    *  $a->body("This is another line");
27    *  $a->gpg_set_key("test2");
28    *  $a->gpg_set_algo("twofish"); //default to AES256 if omitted
29    *  $a->attachment("/webs/development/WhoWroteSobig.pdf");
30    *  if($a->send()) echo "Mail sent"; 
31    * ***************************************************************
32    * If you want to use asymmetrical encryption instead 
33    * (Public Key Infrastructure) you will have to configure a keyring
34    * manually. Then you can use:
35    * $a->gpg_add_key("6b0b9508");
36    * $a->gpg_add_key("789ABCDE");
37    * $a->gpg_set_type(GPG_ASYMMETRIC);
38    * $a->gpg_set_homedir("/webs/development/.gnupg/");
39    * instead. now gpg_set_key is the keys to use and not the password, 
40    * GPG_ASYMMETRIC is a constant to 2, the constant GPG_SYMMETRIC is 1,
41    * but rarely used as it is the default.
42    * 
43    * To use the sign feature you have to set $a->gpg_set_sign(1); this 
44    * require a default key to be defined in the gpg.conf, using a line 
45    * such as default-key  4336E0CB
46    * ***************************************************************
47    * To sign outgoing messages: 
48    * $a = new sendmail_gpgsign;
49    * $a->from("kf@kfwebs.net");
50    * $a->add_to("webmaster@kfwebs.net");
51    * $a->subject("This is the subject - blah");
52    * $a->body("This is a test\n\n");
53    * $a->body("This is another line");
54    * $a->gpg_set_signing_key("0x4336E0CB");
55    * $a->gpg_set_algo("sha512"); // default to sha256
56    * $a->gpg_set_homedir("/webs/development/.gnupg/");
57    * $a->gpg_set_key("6b0b9508");
58    * $a->attachment("/webs/development/img_2670.jpg");
59    * if($a->send()) echo "Mail sent"; 
60    *
61    */
62
63   protected $to = array();
64   protected $cc = array();
65   protected $bcc = array();
66   protected $tos;
67   protected $ccs;
68   protected $bccs;
69   protected $attachment = array();
70   protected $body = "";
71   protected $from = "";
72   protected $subject = "";
73   protected $debug = 0;
74   
75   protected function add_element(&$arr,$add)
76   {
77    if(is_array($add)){$arr = array_merge($arr,$add);}
78     else{array_push($arr, $add);}
79   }
80
81   public function from($email){$this->from = $email;}
82   public function subject($text){$this->subject = $text;}  
83   public function add_to($email){$this->add_element($this->to,$email);}
84   public function add_cc($email){$this->add_element($this->cc,$email);}
85   public function add_bcc($email){$this->add_element($this->bcc,$email);}  
86   public function body($content){$this->body .= $content;}
87   public function debug(){$this->debug=1;}
88   
89   protected function getmimetype($name)
90   {
91    $b = FALSE;
92    $a = array(
93     ".pdf" => "application/pdf",
94     ".ps"  => "application/postscript",
95     ".eps" => "application/postscript",
96     ".sxw" => "application/vnd.sun.xml.writer",
97     ".sxc" => "application/vnd.sun.xml.calc",
98     ".gif" => "image/gif",
99     ".jpg" => "image/jpg",
100     ".png" => "image/png",
101     ".doc" => "application/msword",
102     ".xls" => "application/vnd.ms-excel",
103     ".txt" => "text/plain"
104    );
105    if(isset($a[".".strtolower(substr($name,-3))])) $b = $a[".".strtolower(substr($name,-3))];
106    if(isset($a[".".strtolower(substr($name,-2))])) $b = $a[".".strtolower(substr($name,-2))];
107    return $b;
108   }
109   
110   protected function getheaders()
111   {  
112    $this->tos = implode(",",$this->to);
113    $this->ccs = implode(",",$this->cc);
114    $this->bccs = implode(",",$this->bcc);
115
116    $headers  = "From: {$this->from}\n";
117    $headers .= "MIME-Version: 1.0\n";
118    $headers .= "X-Sender: KF Webs PHP Mail Class [http://www.kfwebs.net] \n";
119    if(strlen($this->ccs)>0) $headers .= "CC: {$this->ccs}\n";
120    if(strlen($this->bccs)>0) $headers .= "BCC: {$this->bccs}\n";
121    return $headers;
122   }
123   
124   public function attachment($path, $type=1, $filename=1)
125   {
126    $fp = fopen($path, 'r');
127    $contents = fread($fp, filesize($path));
128    fclose($fp);
129    if($filename===1) $filename=basename($path);
130    if($type===1)
131    {
132     $type=$this->getmimetype($path);
133     if($type===FALSE) exit("MIME type required for {$path}");
134    }
135    $this->attachment[] = array(chunk_split(base64_encode($contents)),$type,$filename);
136   }
137  }
138
139  class sendmail_ordinary extends sendmail_base
140  {
141   public function send()
142   {
143    $bound = '-----=' . md5(uniqid(rand()));
144    $headers = $this->getheaders();
145    $headers .= "Content-Type: multipart/mixed; boundary=\"{$bound}\"\n";
146    
147    $mime = "";
148    $mime .= "This is a multi-part message in MIME format.\n\n";
149    $mime .= "--{$bound}\nContent-Type: text/plain;charset=\"utf-8\"\nContent-Transfer-Encoding: base64\nContent-Disposition: inline\n\n".chunk_split(base64_encode($this->body))."\n\n";
150    
151    $ac = count($this->attachment);
152    for($i=0;$i<$ac;$i++)
153    {
154     $mime .= "--{$bound}\nContent-Type: {$this->attachment[$i][1]}\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment; filename=\"{$this->attachment[$i][2]}\"\n\n{$this->attachment[$i][0]}\n\n";
155    }
156    $mime .= "--{$bound}--";
157
158    if($this->debug==1) echo "email sent to\n{$tos}\n\nSubject: {$this->subject}\n\nheaders:\n{$headers}\n\nMessage:\n{$mime}\n";
159    return mail($this->tos,$this->subject,$mime, $headers);
160   }
161  }
162  
163
164  class sendmail_gpgbase extends sendmail_base
165  {
166   protected $gpg_path = "/usr/bin/gpg";
167   protected $gpg_tmpdir = "/tmp";
168   protected $gpg_homedir = "";
169   protected $gpg_version = "1.2";
170   
171   public function gpg_set_path($path){$this->gpg_path=escapeshellcmd($path);}
172   public function gpg_set_homedir($dir){$this->gpg_homedir=$dir;}
173   public function gpg_set_tmp($dir){$this->gpg_tmpdir=escapeshellcmd($dir);}  
174   public function gpg_set_version($ver){$this->gpg_version=$ver;}
175  }
176  
177  class sendmail_gpgsign extends sendmail_gpgbase
178  {
179   protected $gpg_signing_key="";
180   protected $gpg_algo = "sha1";
181   
182   public function gpg_set_signing_key($key){$this->gpg_signing_key=escapeshellcmd($key);}
183   public function gpg_set_algo($algo){$this->gpg_algo=escapeshellcmd($algo);}
184   
185   protected function gpg_sign($var)
186   {
187    $tmp=$this->gpg_tmpdir."/kfmail".md5(uniqid(rand()));
188    file_put_contents($tmp,$var);
189    
190    if($this->gpg_homedir=="") die("You need to specify a homedir to use asymmetrical encryption");
191    
192    $gpg_command = "--homedir {$this->gpg_homedir} ".(($this->gpg_version=="1.4") ? " --trust-model always" : " --always-trust")." --no-tty --comment \"KF Webs PHP Mail Class [http://www.kfwebs.net]\" --command-fd 0 -u {$this->gpg_signing_key} -asbt";
193    $gpg_command_use = $this->gpg_path." {$gpg_command} --digest-algo {$this->gpg_algo}";
194    $gpg_command_use = "cat $tmp | $gpg_command_use > $tmp.asc";
195    $a = `$gpg_command_use`;
196    
197    if($this->debug==1)
198    {
199     echo $a;
200     echo $gpg_command_use;
201    }
202    $out= file_get_contents($tmp.".asc");
203    unlink($tmp);
204    unlink($tmp.".asc");
205    return $out;
206   }
207   
208   public function send()
209   {
210    $bound  = '-----=' . md5(uniqid(rand()));
211    $bound2 = '-----=' . md5(uniqid(rand()));
212    
213    $headers = $this->getheaders();
214    $headers .= "Content-Type: multipart/signed; micalg=pgp-{$this->gpg_algo};\n protocol=\"application/pgp-signature\";\n boundary=\"{$bound}\"\n";
215    
216    $mime = "";
217    $pgpmime="";
218
219    $mime .= "This is an OpenPGP/MIME signed message (RFC 2440 and 3156).\n";
220    $mime .= "--{$bound}\n";
221    
222    $pgpmime .= "Content-Type: multipart/mixed;\n boundary=\"{$bound2}\"\n\nThis is a multi-part message in MIME format.\n";
223    $pgpmime .= "--{$bound2}\nContent-Type: text/plain;charset=\"utf-8\"\nContent-Transfer-Encoding: base64\nContent-Disposition: inline\n\n".chunk_split(base64_encode($this->body))."\n\n";
224    
225    $ac = count($this->attachment);
226    for($i=0;$i<$ac;$i++)
227    {
228     $pgpmime .= "--{$bound2}\nContent-Type: {$this->attachment[$i][1]};name=\"{$this->attachment[$i][2]}\"\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment; filename=\"{$this->attachment[$i][2]}\"\n\n{$this->attachment[$i][0]}\n";
229    }
230    $pgpmime .= "\n--{$bound2}--\n\n";
231    
232    $mime .= $pgpmime;
233    $mime .= "\n--{$bound}\nContent-Type: application/pgp-signature; name=\"signature.asc\"\nContent-Description: OpenPGP digital signature\nContent-Disposition: attachment; filename=\"signature.asc\"\n\n";
234    $mime .= $this->gpg_sign($pgpmime);
235    $mime .= "\n--{$bound}--";
236    if($this->debug==1) echo "email sent to\n{$tos}\n\nSubject: {$this->subject}\n\nheaders:\n{$headers}\n\nMessage:\n{$mime}\n";
237    return mail($this->tos,$this->subject,$mime, $headers);
238   }
239  }
240  
241  class sendmail_gpg extends sendmail_gpgbase
242  {
243   
244   protected $gpg_key = "abcd";
245   protected $gpg_algo = "aes256";
246   protected $gpg_command = "";
247   protected $gpg_command_use = "";  
248   protected $gpg_type = 1; // 1 is symmetrical, 2 is asymmetrical
249   protected $gpg_sign = 0; // 0: NO ; 1: YES
250   protected $gpg_keys = array();
251   protected $gpg_signing_key="";
252
253   public function gpg_set_key($key){$this->gpg_key = escapeshellcmd($key);}
254   public function gpg_set_algo($algo){$this->gpg_algo=escapeshellcmd($algo);}
255   public function gpg_set_type($type){$this->gpg_type=$type;}
256   public function gpg_set_sign($sign){$this->gpg_sign=$sign;}
257   public function gpg_add_key($key){$this->add_element($this->gpg_keys,$key);}  
258   public function gpg_set_signing_key($key)
259   {
260    $this->gpg_signing_key=escapeshellcmd($key);
261    $this->gpg_set_type(2);
262    $this->gpg_set_sign(1);
263   }
264   
265   protected function gpg_encrypt($var)
266   {
267    if(count($this->gpg_keys)<1 && $this->gpg_key != "" && $this->gpg_key != "abcd")
268    {
269     $this->gpg_keys[] = $this->gpg_key;
270    }
271    
272    $tmp=$this->gpg_tmpdir."/kfmail".md5(uniqid(rand()));
273    file_put_contents($tmp,$var);
274    if($this->gpg_type==2)
275    {
276     $gpg_key_list = "";
277     if($this->gpg_homedir=="") die("You need to specify a homedir to use asymmetrical encryption");
278     $this->gpg_command = "--homedir {$this->gpg_homedir} ".(($this->gpg_version=="1.4") ? " --trust-model always" : " --always-trust")." --no-tty --comment \"KF Webs PHP Mail Class [http://www.kfwebs.net]\" --command-fd 0 ".(($this->gpg_signing_key!="") ? " -u {$this->gpg_signing_key} " : "")."-a".(($this->gpg_sign==1) ? "s" : "")."e";
279     foreach($this->gpg_keys as $abcd)
280     {
281      $gpg_key_list .= " -r {$abcd}";
282     }
283     $this->gpg_command_use = $this->gpg_path." --cipher-algo ".$this->gpg_algo." ".$this->gpg_command." {$gpg_key_list} ".$tmp." 2>&1";
284    }
285    else
286    {
287     $this->gpg_command = "--homedir /tmp/ --no-tty --comment \"KF Webs PHP Mail Class [http://www.kfwebs.net]\" --command-fd 0 -ac";
288     $this->gpg_command_use = "echo \"{$this->gpg_key}\" | ".$this->gpg_path." --cipher-algo ".$this->gpg_algo." ".$this->gpg_command." ".$tmp." 2>&1";
289    }
290    $a = `$this->gpg_command_use`;
291    if($this->debug==1) echo $a;
292    $out= file_get_contents($tmp.".asc");
293    unlink($tmp);
294    unlink($tmp.".asc");
295    return $out;
296   }
297
298   public function send()
299   {
300    $bound  = '-----=' . md5(uniqid(rand()));
301    $bound2 = '-----=' . md5(uniqid(rand()));
302    
303    $headers = $this->getheaders();
304    $headers .= "Content-Type: multipart/encrypted; protocol=\"application/pgp-encrypted\"; boundary=\"{$bound}\"\n";
305    
306    $mime = "";
307    $pgpmime="";
308
309    $mime .= "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156).\n";
310    
311    $mime .= "--{$bound}\nContent-Type: application/pgp-encrypted\nContent-Description: PGP/MIME version identification\n\nVersion: 1\n\n";
312    $mime .= "--{$bound}\nContent-Type: application/octet-stream; name=\"encrypted.asc\"\nContent-Description: OpenPGP encrypted message\nContent-Disposition: inline; filename=\"encrypted.asc\"\n\n";
313    $pgpmime .= "Content-Type: multipart/mixed;boundary=\"{$bound2}\"\n\nThis is a multi-part message in MIME format.\n\n";
314    $pgpmime .= "--{$bound2}\nContent-Type: text/plain;charset=\"utf-8\"\nContent-Transfer-Encoding: base64\nContent-Disposition: inline\n\n".chunk_split(base64_encode($this->body))."\n\n";
315    
316    $ac = count($this->attachment);
317    for($i=0;$i<$ac;$i++)
318    {
319     $pgpmime .= "--{$bound2}\nContent-Type: {$this->attachment[$i][1]};name=\"{$this->attachment[$i][2]}\"\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment; filename=\"{$this->attachment[$i][2]}\"\n\n{$this->attachment[$i][0]}\n";
320    }
321    $pgpmime .= "\n--{$bound2}--\n\n";
322    $mime .= $this->gpg_encrypt($pgpmime);
323    $mime .= "\n--{$bound}--";
324    if($this->debug==1) echo "email sent to\n{$tos}\n\nSubject: {$this->subject}\n\nheaders:\n{$headers}\n\nMessage:\n{$mime}\n";
325    return mail($this->tos,$this->subject,$mime, $headers);
326   }
327  }
328  class sendmail extends sendmail_gpg{} // For easability
329 ?>