source: t29-www/lib/mail/mailer.php @ 580

Last change on this file since 580 was 477, checked in by sven, 10 years ago

Anmeldeformular: Captchas wegen Spambefall aktiviert.

(mailer: Kein die, wenn Recaptcha-Key nicht bekannt ist)

File size: 9.6 KB
Line 
1<?php
2
3/**
4 * New generic formmailer for technikum29 infrastructure
5 **/
6
7$maillib = dirname(__FILE__);
8require "$maillib/recaptchalib.php";
9
10$key_file = "$maillib/recaptcha_keys.php";
11$recaptcha_keys_loaded = null;
12if(file_exists($key_file)) {
13        include $key_file;
14        // now in global scope:
15        // $publickey, recaptcha_get_answer, recaptcha_get_html etc.
16        $recaptcha_keys_loaded = true;
17} else
18        $recaptcha_keys_loaded = false;
19 
20// This script can be used as standalone or libary.
21if(realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__) {
22        $mailer = new t29Mailer($_REQUEST);
23        $mailer->run();
24}
25
26class t29Mailer {
27        function print_usage() {
28                // problem: vars kriegt man nicht global, require include raum auch nicht global.
29                // bad design.
30                /*global $seiten_id, $version, $titel, $dynamischer_inhalt, $lib;
31                $seiten_id = 'mailer';
32                $version = '$Id$';
33                $titel = "t29v6 form mailer usage";
34                $dynamischer_inhalt = true;
35
36                $lib = "./";
37                require "$lib/technikum29.php";*/
38?>
39<html>
40<h2>Usage</h2>
41
42<p>This small mail system is capable of:
43
44<ul>
45        <li>Mail to upstream and acknowledgement mail back to sender
46        <li>Template based or individual output page with arguments
47</ul>
48
49
50<h3>Get or Post variables</h3>
51<table>
52<tr><th>name <th>default value <th>interpretation
53<tr><th>to   <td>sven          <td>one e-mail prefix, will be used with <tt>@technikum29.de</tt>,
54                                   so mail goes to e.g. <tt>thevalue@technikum29.de</tt>.
55<tr><th>subject <td>           <td>Subject of the mail. Can contain template variables like {foo}, where foo is some other
56                                   variable.
57<tr><th>body<td>                <td>Body of the mail. Can contain template variables.
58                                   
59
60<tr><th>ack   <td>false/no      <td>Give true/yes for sending an ack mail.
61<tr><th>ack_to <td>            <td>Target adress to send acknowledgement mail to. Can contain template variables like {data_sender_mail}.
62<tr><th>ack_subject <td>       <td>Like subject, but for ack mail.
63<tr><th>ack_body <td>    <td>Like body.
64
65
66</table>
67
68        <?php } // end of method print_usage()
69       
70        // the small data holding architecture
71        public $_values;
72        // Security: Captcha checking not on $_values basis since that is regularily provided by
73        // POST or REQUEST data which are directly given by user => spambots could disable captcha check
74        public $enable_captcha_check = true;
75       
76        function __construct(Array $data=array()) {
77                // default values
78                $default_values = array(
79                        "to" => "sven",
80                        "subject" => "technikum29 form mailer",
81                        "body" => null,
82                        "ack" => false,
83                       
84                        'header' => null, // has to be array
85                       
86                        "output_success_page" => '<html><h2>Mail successfully sent</h2><p>Thank you for your mail.</p>',
87                        "output_error_page" => function($mailer, $error) {
88                                ?><html>
89                                <h1>Errors in mail</h1>
90                                <form method="POST">
91                                        <p>Please fill out this captcha to send the mail. We don't like spam:</p>
92                                        <?php $mailer->print_serialized_hidden_form(); ?>
93                                        <?php echo $error; ?>
94                                        <input type="submit" value="Yes I am human">
95                                </form><?php
96                        },
97                       
98                        "mail_info_append_text" => function($mailer) {
99                                $time = date('r');
100                                $ret = <<<EOT
101
102Diese Mail wurde mit einem der technikum29 Web-Form-Mailer geschickt,
103und zwar dem t29v6-NG Formmailer. Ein Besucher hat also auf einer Webseite
104im technikum29.de-Angebot ein Formular ausgefüllt und daraufhin wurde
105diese Mail verschickt.
106
107Adresse wo Benutzer herkam: $_SERVER[HTTP_REFERER]
108Zeit, zu der der Besucher die Mail verschickte: $time
109Browser des Benutzers (User-Agent): $_SERVER[HTTP_USER_AGENT]
110IP-Adresse des Besuchers: $_SERVER[REMOTE_ADDR]
111
112EOT;
113
114                                if($mailer->ack) $ret .= <<<EOT1
115
116Der Besucher bekam dafür eine Bestätigungsmail an die Adresse
117{$mailer->ack_to}  .
118
119EOT1;
120                                return $ret; },
121                       
122                        "recaptcha_challenge_field" => false,
123                        "recaptcha_response_field" => false
124                ); // end of default values
125               
126                // merge given values
127                $this->_values = array_merge($default_values, $data);
128        } // end of constructor
129       
130       
131        public function __set($property, $value){
132                return $this->_values[$property] = $value;
133        }
134
135        public function __get($property){
136                return array_key_exists($property, $this->_values)
137                        ? $this->_values[$property]
138                        #: #(array_key_exists($property, $this->default_values)
139                        #       ? $this->default_values[$property]
140                                : null;
141        }
142        public function __isset($property) {
143                return isset($this->$property) || isset($this->_values[$property]); # || isset($this->default_values[$property]);
144        }
145       
146        // the system
147        public function run() {
148                global $recaptcha_keys_loaded;
149       
150                if(empty($this->_values)) {
151                        $this->print_usage();
152                        return;
153                }
154               
155                // check captcha and check presence of important field
156                if(!$this->to || !$this->body) {
157                        // bubu
158                }
159               
160                // show captcha validation, if neccessary
161                if($recaptcha_keys_loaded && $this->enable_captcha_check && !$this->check_captcha()) {
162                        return false;
163                }
164               
165                // send the ACK mail, if appropriate
166                if($this->ack) {
167                        $this->ack_to = $this->call_or_return_callback('ack_to');
168                        $this->ack_subject = $this->call_or_return_callback('ack_subject');
169                        $this->ack_body = $this->call_or_return_callback('ack_body');
170                        $this->send_mail($this->ack_to, $this->ack_subject, $this->ack_body);
171                }
172               
173                // send the mail to t29
174                $this->to .= '@technikum29.de';
175                $this->body = $this->call_or_return_callback('body');
176                $this->body .= $this->call_or_return_callback('mail_info_append_text');
177                $this->subject = $this->call_or_return_callback('subject');
178                $this->send_mail($this->to, $this->subject, $this->body);
179               
180                // show output page
181                $this->show_output_page('success');
182               
183                return true;
184        }
185       
186        public function send_mail($to, $subject, $message_body)  {
187                // compose the header
188                $header = is_array($this->header) ? $this->header : array();
189                $testset = function($k, $v) use(&$header) { if(!isset($header[$k])) $header[$k] = $v; };
190
191                $testset('Content-Type', 'text/plain; charset=UTF-8'); // all t29v6 is utf-8 based!
192                $testset('From', 'technikum29 Computer Musem Webmailer <www@technikum29.de>');
193               
194                $additional_headers = join("\r\n", array_map(function($k) use(&$header) { return "$k: ".$header[$k]; }, array_keys($header)));
195       
196                // debug output
197                $debug_mail = function($t, $s, $m, $a) {
198                        print "<div class='hidden'>";
199                        print "<h2>Debug Mail Output</h2>";
200                        print "<dl><dt>To<dd>$t <dt>Subject <dd>$s <dt>Message <dd><pre>$m</pre> <dt>Add. Headers <dd><pre>$a</pre></dl>";
201                        print "</div>";
202                };
203               
204                $debug_mail($to, $subject, $message_body, $additional_headers);
205                mail($to, $subject, $message_body, $additional_headers);
206        }
207       
208
209        public static function recaptcha_get_publickey() {
210                global $publickey;
211                return $publickey;
212        }
213        public static function recaptcha_get_html() {
214                global $publickey;
215                if ($publickey == null || $publickey == '') {
216                        // recaptcha_get_html wirft sonst ein die().
217                        return '<b>t29Error: Recaptcha Publickey not loaded!</b>';
218                }
219                return recaptcha_get_html($publickey);
220        }
221       
222        public function print_serialized_hidden_form() {
223                // serialize obect to hidden form elements
224                foreach($this->_values as $k => $v) {
225                        if(!is_string($v)) continue;
226                        printf("\t<input type='hidden' name='%s' value='%s'>\n", $k, htmlentities($v, ENT_QUOTES | ENT_HTML401));
227                }
228        }
229       
230        public function call_or_return_callback($property, $additional_argument=null) {
231                if(!isset($this->_values[$property]))
232                        return null;
233                if(is_callable($this->_values[$property])) {
234                        return call_user_func($this->_values[$property], $this, $additional_argument);
235                }
236                elseif(is_string($this->_values[$property])) {
237                        // make string replacements
238                        $mailer = $this; // PHP 5.3 convenience
239                        return preg_replace_callback("/\{([^}]+)\}/", function($match) use ($mailer) {
240                                $identifier = $match[1];
241                                return isset($mailer->_values[$identifier])
242                                        ? $mailer->_values[$identifier]
243                                        : "{?$identifier?}";
244                        }, $this->_values[$property]);
245                }
246               
247        }
248       
249        public function call_or_print_callback($property, $additional_argument=null) {
250                $ret = $this->call_or_return_callback($property, $additional_argument);
251                if($ret != null) print $ret;
252                return true;
253        }
254       
255        public function show_output_page($type, $additional_argument=null) {
256                $id = "output_${type}_page";
257                $this->call_or_print_callback($id, $additional_argument);
258        }
259       
260
261        /**
262         * Check the Recaptcha challenge status and display an error page if
263         * neccessary
264         **/
265        public function check_captcha() {
266                global $publickey;
267                $resp = $this->check_captcha_answer();
268               
269                if($resp === null) {
270                        $page = recaptcha_get_html($publickey);
271                        $this->show_output_page('error', $page);
272                        return false;
273                } else if(!$resp->is_valid) {
274                        // display page
275                        $page = recaptcha_get_html($publickey, $resp->error);
276                        $this->show_output_page('error', $page);
277                        return false;
278                } else {
279                        // valid answer
280                        return true;
281                }
282        }
283       
284        /**
285         * Check the Captcha challenge field.
286         * Return value is a Response object which basically allows to
287         * differ three states:
288         *   $ret == null => no challenge answer present
289         *   $ret->is_valid == true => captcha answered valid (human detected)
290         *   $ret->is_valud == false => captcha answered false (no human detected)
291         *
292         * You can use $ret->error for a further call of
293         *   recaptcha_get_html($publickey, $ret->error);
294         *
295         * @returns librecaptcha Result object
296         **/
297        public function check_captcha_answer() {
298                global $publickey, $privatekey;
299               
300                # the response from reCAPTCHA
301                $resp = null;
302                # the error code from reCAPTCHA, if any
303                $error = null;
304                # display captcha? default: yes!
305                $display_captcha = true;
306
307                if(!$this->recaptcha_challenge_field || !$this->recaptcha_response_field)
308                        return null;
309       
310                $resp = recaptcha_check_answer ($privatekey,
311                        $_SERVER["REMOTE_ADDR"],
312                        $this->recaptcha_challenge_field,
313                        $this->recaptcha_response_field);
314                return $resp;
315        }
316} // end of class t29Mailer
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License