1<?php 2 3/* Modern Contact Plugin for Dokuwiki 4 * 5 * Copyright (C) 2008 Bob Baddeley (bobbaddeley.com) 6 * Copyright (C) 2010-2012 Marvin Thomas Rabe (marvinrabe.de) 7 * 8 * This program is free software; you can redistribute it and/or modify it under the terms 9 * of the GNU General Public License as published by the Free Software Foundation; either 10 * version 3 of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 * See the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along with this program; 17 * if not, see <http://www.gnu.org/licenses/>. */ 18 19/** 20 * Embed a contact form onto any page 21 * @license GNU General Public License 3 <http://www.gnu.org/licenses/> 22 * @author Bob Baddeley <bob@bobbaddeley.com> 23 * @author Marvin Thomas Rabe <mrabe@marvinrabe.de> 24 */ 25 26if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 27if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 28require_once(DOKU_PLUGIN.'syntax.php'); 29require_once(DOKU_INC.'inc/auth.php'); 30require_once(dirname(__file__).'/recaptchalib.php'); 31 32class syntax_plugin_moderncontact extends DokuWiki_Syntax_Plugin { 33 34 public static $captcha = false; 35 public static $lastFormId = 1; 36 37 private $formId = 0; 38 private $status = 1; 39 private $statusMessage; 40 private $errorFlags = array(); 41 42 /** 43 * General information about the plugin. 44 */ 45 public function getInfo(){ 46 return array( 47 'author' => 'Marvin Thomas Rabe', 48 'email' => 'mrabe@marvinrabe.de', 49 'date' => '2012-06-06', 50 'name' => 'Modern Contact Plugin', 51 'desc' => 'Creates a contact form to email the webmaster. Secured with recaptcha.', 52 'url' => 'https://github.com/marvinrabe/dokuwiki-contact', 53 ); 54 } 55 56 /** 57 * What kind of syntax are we? 58 */ 59 public function getType(){ 60 return 'container'; 61 } 62 63 /** 64 * What about paragraphs? 65 */ 66 public function getPType(){ 67 return 'block'; 68 } 69 70 /** 71 * Where to sort in? 72 */ 73 public function getSort(){ 74 return 300; 75 } 76 77 /** 78 * Connect pattern to lexer. 79 */ 80 public function connectTo($mode) { 81 $this->Lexer->addSpecialPattern('\{\{contact>[^}]*\}\}',$mode,'plugin_moderncontact'); 82 } 83 84 /** 85 * Handle the match. 86 */ 87 public function handle($match, $state, $pos, &$handler){ 88 if (isset($_REQUEST['comment'])) 89 return false; 90 91 $match = substr($match,10,-2); //strip markup from start and end 92 93 $data = array(); 94 95 //handle params 96 $params = explode('|',$match); 97 foreach($params as $param){ 98 $splitparam = explode('=',$param); 99 $data[$splitparam[0]] = $splitparam[1]; 100 } 101 return $data; 102 } 103 104 /** 105 * Create output. 106 */ 107 public function render($mode, &$renderer, $data) { 108 if($mode == 'xhtml'){ 109 // Define unique form id 110 $this->formId = syntax_plugin_moderncontact::$lastFormId++; 111 112 // Disable cache 113 $renderer->info['cache'] = false; 114 $renderer->doc .= $this->_contact($data); 115 return true; 116 } 117 return false; 118 } 119 120 /** 121 * Verify and send email content.´ 122 */ 123 protected function _send_contact($captcha=false){ 124 global $conf; 125 global $auth; 126 $lang = $this->getLang("error"); 127 128 require_once(DOKU_INC.'inc/mail.php'); 129 $name = $_POST['name']; 130 $email = $_POST['email']; 131 $subject = $_POST['subject']; 132 $comment = $name."\r\n"; 133 $comment .= $email."\r\n\n"; 134 $comment .= $_POST['content']; 135 if (isset($_REQUEST['to'])){ 136 $user = $auth->getUserData($_POST['to']); 137 if (isset($user)) { 138 $to = $user['mail']; 139 } 140 } else { 141 $to = $this->getConf('default'); 142 } 143 144 // name entered? 145 if(strlen($name) < 2) 146 $this->_set_error('name', $lang["name"]); 147 148 // email correctly entered? 149 if(!$this->_check_email_address($email)) 150 $this->_set_error('email', $lang["email"]); 151 152 // comment entered? 153 if(strlen($_POST['content']) < 10) 154 $this->_set_error('content', $lang["content"]); 155 156 // checks recaptcha answer 157 if($conf['plugin']['moderncontact']['captcha'] == 1 && $captcha == true) { 158 $resp = recaptcha_check_answer ($conf['plugin']['moderncontact']['recaptchasecret'], 159 $_SERVER["REMOTE_ADDR"], 160 $_POST["recaptcha_challenge_field"], 161 $_POST["recaptcha_response_field"]); 162 if (!$resp->is_valid){ 163 $this->_set_error('captcha', $lang["captcha"]); 164 } 165 } 166 167 // A bunch of tests to make sure it's legitimate mail and not spoofed 168 // This should make it not very easy to do injection 169 if (eregi("\r",$name) || eregi("\n",$name) || eregi("MIME-Version: ",$name) || eregi("Content-Type: ",$name)){ 170 $this->_set_error('name', $lang["valid_name"]); 171 } 172 if (eregi("\r",$email) || eregi("\n",$email) || eregi("MIME-Version: ",$email || eregi("Content-Type: ",$email))){ 173 $this->_set_error('email', $lang["valid_email"]); 174 } 175 if (eregi("\r",$subject) || eregi("\n",$subject) || eregi("MIME-Version: ",$subject) || eregi("Content-Type: ",$subject)){ 176 $this->_set_error('subject', $lang["valid_subject"]); 177 } 178 if (eregi("\r",$to) || eregi("\n",$to) || eregi("MIME-Version: ",$to) || eregi("Content-Type: ",$to)){ 179 $this->_set_error('to', $lang["valid_to"]); 180 } 181 if (eregi("MIME-Version: ",$comment) || eregi("Content-Type: ",$comment)){ 182 $this->_set_error('content', $lang["valid_content"]); 183 } 184 185 // Status has not changed. 186 if($this->status != 0) { 187 // send only if comment is not empty 188 // this should never be the case anyway because the form has 189 // validation to ensure a non-empty comment 190 if (trim($comment, " \t") != ''){ 191 if (mail_send($to, $subject, $comment, $email, '', '', 'Reply-to: '.$email)){ 192 $this->statusMessage = $this->getLang("success"); 193 } else { 194 $this->_set_error('unknown', $lang["unknown"]); 195 } 196 //we're using the included mail_send command because it's 197 //already there and it's easy to use and it works 198 } 199 } 200 201 return true; 202 } 203 204 /** 205 * Manage error messages. 206 */ 207 protected function _set_error($type, $message) { 208 $this->status = 0; 209 $this->statusMessage .= empty($this->statusMessage)?$message:'<br>'.$message; 210 $this->errorFlags[$type] = true; 211 } 212 213 /** 214 * Validate email address. From: http://www.ilovejackdaniels.com/php/email-address-validation 215 */ 216 protected function _check_email_address($email) { 217 // First, we check that there's one @ symbol, 218 // and that the lengths are right. 219 if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) { 220 // Email invalid because wrong number of characters 221 // in one section or wrong number of @ symbols. 222 return false; 223 } 224 // Split it into sections to make life easier 225 $email_array = explode("@", $email); 226 $local_array = explode(".", $email_array[0]); 227 for ($i = 0; $i < sizeof($local_array); $i++) { 228 if (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", 229 $local_array[$i])) { 230 return false; 231 } 232 } 233 // Check if domain is IP. If not, 234 // it should be valid domain name 235 if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) { 236 $domain_array = explode(".", $email_array[1]); 237 if (sizeof($domain_array) < 2) { 238 return false; // Not enough parts to domain 239 } 240 for ($i = 0; $i < sizeof($domain_array); $i++) { 241 if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", 242 $domain_array[$i])) { 243 return false; 244 } 245 } 246 } 247 return true; 248 } 249 250 /** 251 * Does the contact form xhtml creation. 252 */ 253 protected function _contact($data){ 254 global $conf; 255 global $USERINFO; 256 257 // Is there none captche on the side? 258 $captcha = ($conf['plugin']['moderncontact']['captcha'] == 1 && syntax_plugin_moderncontact::$captcha == false)?true:false; 259 260 $ret = "<form action=\"".$_SERVER['REQUEST_URI']."#form-".$this->formId."\" method=\"POST\"><a name=\"form-".$this->formId."\"></a>"; 261 $ret .= "<table class=\"inline\">"; 262 263 // Send message and give feedback 264 if (isset($_POST['submit-form-'.$this->formId])) 265 if($this->_send_contact($captcha)) 266 $ret .= $this->_show_message(); 267 268 // Build table 269 $ret .= $this->_table_row($this->getLang("name"), 'name', 'text', $USERINFO['name']); 270 $ret .= $this->_table_row($this->getLang("email"), 'email', 'text', $USERINFO['mail']); 271 if (!isset($data['subj'])) 272 $ret .= $this->_table_row($this->getLang("subject"), 'subject', 'text'); 273 $ret .= $this->_table_row($this->getLang("content"), 'content', 'textarea'); 274 275 // Captcha 276 if($captcha) { 277 if($this->errorFlags["captcha"]) { 278 $ret .= '<style>#recaptcha_response_field { border: 1px solid #e18484 !important; }</style>'; 279 } 280 $ret .= "<tr><td colspan=\"2\">" 281 . "<script type=\"text/javascript\">var RecaptchaOptions = { lang : '".$conf['lang']."', " 282 . "theme : '".$conf['plugin']['moderncontact']['recaptchalayout']."' };</script>" 283 . recaptcha_get_html($conf['plugin']['moderncontact']['recaptchakey'])."</td></tr>"; 284 syntax_plugin_moderncontact::$captcha = true; 285 } 286 287 $ret .= "</table><p>"; 288 if (isset($data['subj'])) 289 $ret .= "<input type=\"hidden\" name=\"subject\" value=\"".$data['subj']."\" />"; 290 if (isset($data['to'])) 291 $ret .= "<input type=\"hidden\" name=\"to\" value=\"".$data['to']."\" />"; 292 $ret .= "<input type=\"hidden\" name=\"do\" value=\"show\" />"; 293 $ret .= "<input type=\"submit\" name=\"submit-form-".$this->formId."\" value=\"".$this->getLang("contact")."\" />"; 294 $ret .= "</p></form>"; 295 296 return $ret; 297 } 298 299 /** 300 * Show up error messages. 301 */ 302 protected function _show_message() { 303 return '<tr><td colspan="2">' 304 . '<p class="'.(($this->status == 0)?'contact_error':'contact_success').'">'.$this->statusMessage.'</p>' 305 . '</td></tr>'; 306 } 307 308 /** 309 * Renders a table row. 310 */ 311 protected function _table_row($label, $name, $type, $default='') { 312 $value = (isset($_POST['submit-form-'.$this->formId]) && $this->status == 0)?$_POST[$name]:$default; 313 $class = ($this->errorFlags[$name])?'class="error_field"':''; 314 $row = '<tr><td>'.$label.'</td><td>'; 315 if($type == 'textarea') 316 $row .= '<textarea name="'.$name.'" wrap="on" cols="40" rows="6" '.$class.'>'.$value.'</textarea>'; 317 else 318 $row .= '<input type="'.$type.'" value="'.$value.'" name="'.$name.'" '.$class.'>'; 319 $row .= '</td></tr>'; 320 return $row; 321 } 322 323} 324