1<?php 2/** 3 * Mail functions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9// end of line for mail lines - RFC822 says CRLF but postfix (and other MTAs?) 10// think different, also PHP >=8.0.14 mail() has changed. 11if(!defined('MAILHEADER_EOL')) { 12 if (version_compare(phpversion(), '8.0.14') < 0) // See https://github.com/php/php-src/issues/8086 13 define('MAILHEADER_EOL', "\n"); 14 else 15 define('MAILHEADER_EOL', "\r\n"); 16} 17#define('MAILHEADER_ASCIIONLY',1); 18 19/** 20 * Patterns for use in email detection and validation 21 * 22 * NOTE: there is an unquoted '/' in RFC2822_ATEXT, it must remain unquoted to be used in the parser 23 * the pattern uses non-capturing groups as captured groups aren't allowed in the parser 24 * select pattern delimiters with care! 25 * 26 * May not be completly RFC conform! 27 * @link http://www.faqs.org/rfcs/rfc2822.html (paras 3.4.1 & 3.2.4) 28 * 29 * @author Chris Smith <chris@jalakai.co.uk> 30 * Check if a given mail address is valid 31 */ 32if (!defined('RFC2822_ATEXT')) define('RFC2822_ATEXT',"0-9a-zA-Z!#$%&'*+/=?^_`{|}~-"); 33if (!defined('PREG_PATTERN_VALID_EMAIL')) define( 34 'PREG_PATTERN_VALID_EMAIL', 35 '['.RFC2822_ATEXT.']+(?:\.['.RFC2822_ATEXT.']+)*@(?i:[0-9a-z][0-9a-z-]*\.)+(?i:[a-z]{2,63})' 36); 37 38/** 39 * Prepare mailfrom replacement patterns 40 * 41 * Also prepares a mailfromnobody config that contains an autoconstructed address 42 * if the mailfrom one is userdependent and this might not be wanted (subscriptions) 43 * 44 * @author Andreas Gohr <andi@splitbrain.org> 45 */ 46function mail_setup(){ 47 global $conf; 48 global $USERINFO; 49 /** @var Input $INPUT */ 50 global $INPUT; 51 52 // auto constructed address 53 $host = @parse_url(DOKU_URL,PHP_URL_HOST); 54 if(!$host) $host = 'example.com'; 55 $noreply = 'noreply@'.$host; 56 57 $replace = array(); 58 if(!empty($USERINFO['mail'])){ 59 $replace['@MAIL@'] = $USERINFO['mail']; 60 }else{ 61 $replace['@MAIL@'] = $noreply; 62 } 63 64 // use 'noreply' if no user 65 $replace['@USER@'] = $INPUT->server->str('REMOTE_USER', 'noreply', true); 66 67 if(!empty($USERINFO['name'])){ 68 $replace['@NAME@'] = $USERINFO['name']; 69 }else{ 70 $replace['@NAME@'] = ''; 71 } 72 73 // apply replacements 74 $from = str_replace(array_keys($replace), 75 array_values($replace), 76 $conf['mailfrom']); 77 78 // any replacements done? set different mailfromnone 79 if($from != $conf['mailfrom']){ 80 $conf['mailfromnobody'] = $noreply; 81 }else{ 82 $conf['mailfromnobody'] = $from; 83 } 84 $conf['mailfrom'] = $from; 85} 86 87/** 88 * Check if a given mail address is valid 89 * 90 * @param string $email the address to check 91 * @return bool true if address is valid 92 */ 93function mail_isvalid($email) { 94 return EmailAddressValidator::checkEmailAddress($email, true); 95} 96 97/** 98 * Quoted printable encoding 99 * 100 * @author umu <umuAThrz.tu-chemnitz.de> 101 * @link http://php.net/manual/en/function.imap-8bit.php#61216 102 * 103 * @param string $sText 104 * @param int $maxlen 105 * @param bool $bEmulate_imap_8bit 106 * 107 * @return string 108 */ 109function mail_quotedprintable_encode($sText,$maxlen=74,$bEmulate_imap_8bit=true) { 110 // split text into lines 111 $aLines= preg_split("/(?:\r\n|\r|\n)/", $sText); 112 $cnt = count($aLines); 113 114 for ($i=0;$i<$cnt;$i++) { 115 $sLine =& $aLines[$i]; 116 if (strlen($sLine)===0) continue; // do nothing, if empty 117 118 $sRegExp = '/[^\x09\x20\x21-\x3C\x3E-\x7E]/e'; 119 120 // imap_8bit encodes x09 everywhere, not only at lineends, 121 // for EBCDIC safeness encode !"#$@[\]^`{|}~, 122 // for complete safeness encode every character :) 123 if ($bEmulate_imap_8bit) 124 $sRegExp = '/[^\x20\x21-\x3C\x3E-\x7E]/'; 125 126 $sLine = preg_replace_callback( $sRegExp, 'mail_quotedprintable_encode_callback', $sLine ); 127 128 // encode x09,x20 at lineends 129 { 130 $iLength = strlen($sLine); 131 $iLastChar = ord($sLine[$iLength-1]); 132 133 // !!!!!!!! 134 // imap_8_bit does not encode x20 at the very end of a text, 135 // here is, where I don't agree with imap_8_bit, 136 // please correct me, if I'm wrong, 137 // or comment next line for RFC2045 conformance, if you like 138 if (!($bEmulate_imap_8bit && ($i==count($aLines)-1))){ 139 if (($iLastChar==0x09)||($iLastChar==0x20)) { 140 $sLine[$iLength-1]='='; 141 $sLine .= ($iLastChar==0x09)?'09':'20'; 142 } 143 } 144 } // imap_8bit encodes x20 before chr(13), too 145 // although IMHO not requested by RFC2045, why not do it safer :) 146 // and why not encode any x20 around chr(10) or chr(13) 147 if ($bEmulate_imap_8bit) { 148 $sLine=str_replace(' =0D','=20=0D',$sLine); 149 //$sLine=str_replace(' =0A','=20=0A',$sLine); 150 //$sLine=str_replace('=0D ','=0D=20',$sLine); 151 //$sLine=str_replace('=0A ','=0A=20',$sLine); 152 } 153 154 // finally split into softlines no longer than $maxlen chars, 155 // for even more safeness one could encode x09,x20 156 // at the very first character of the line 157 // and after soft linebreaks, as well, 158 // but this wouldn't be caught by such an easy RegExp 159 if($maxlen){ 160 preg_match_all( '/.{1,'.($maxlen - 2).'}([^=]{0,2})?/', $sLine, $aMatch ); 161 $sLine = implode( '=' . MAILHEADER_EOL, $aMatch[0] ); // add soft crlf's 162 } 163 } 164 165 // join lines into text 166 return implode(MAILHEADER_EOL,$aLines); 167} 168 169function mail_quotedprintable_encode_callback($matches){ 170 return sprintf( "=%02X", ord ( $matches[0] ) ) ; 171} 172