MTA
[ class tree: MTA ] [ index: MTA ] [ all elements ]

Source for file MTA_Generate.php

Documentation is available at MTA_Generate.php

  1. <?php
  2. /**
  3.  * Project: MTA_Generate :: generating mail section abstraction layer<br />
  4.  * File:    MTA/MTA_Generate.php
  5.  *
  6.  * MTA_Generate class는 메일 발송 내용을 구성하기 위한 추상
  7.  * 레이어를 제공한다.
  8.  *
  9.  * @category   Networking
  10.  * @package    MTA
  11.  * @subpackage MTA_Generate
  12.  * @author     JoungKyun.Kim <http://oops.org>
  13.  * @copyright  (c) 2018, OOPS.og
  14.  * @license    BSD License
  15.  * @link       http://pear.oops.org/package/MTA
  16.  * @filesource
  17.  */
  18.  
  19. /**
  20.  * import MTA_Socket class
  21.  */
  22. require_once 'MTA/MTA_Socket.php';
  23.  
  24. /**
  25.  * 메일 발송 내용을 구성하기 위한 추상 레이어
  26.  *
  27.  * @package MTA
  28.  */
  29. Class MTA_Generate extends MTA_Socket {
  30.     // {{{ properties
  31.     /**#@+
  32.      * @access protected
  33.      */
  34.     /**
  35.      * global top level domain
  36.      * @var array 
  37.      */
  38.     protected $gTLD = array (
  39.         'com''net''org''edu''gov''mil',
  40.         'aero''asia''biz''coop''info''int',
  41.         'jobs''museum''name''pro''trabel',
  42.         'cat''mobi''post''tel''xxx''arpa'
  43.     );
  44.  
  45.     /**
  46.      * country code top level domain
  47.      * @var array 
  48.      */
  49.     protected $ccTLD = array (
  50.         'ac''ad''ae''af''ag''ai''al''am''an''ao',
  51.         'aq''ar''as''at''au''aw''ax''az''ba''bb',
  52.         'bd''be''bf''bg''bh''bi''bj''bl''bm''bn',
  53.         'bo''bq''br''bs''bt''bv''bw''by''bz''ca',
  54.         'cc''cd''cf''cg''ch''ci''ck''cl''cm''cn',
  55.         'co''cr''cu''cv''cw''cx''cy''cz''de''dj',
  56.         'dk''dm''do''dz''ec''ee''eg''eh''er''es',
  57.         'et''eu''fi''fj''fk''fm''fo''fr''ga''gb',
  58.         'gd''ge''gf''gg''gh''gi''gl''gm''gn''gp',
  59.         'gq''gr''gs''gt''gu''gw''gy''hk''hm''hn',
  60.         'hr''ht''hu''id''ie''il''im''in''io''iq',
  61.         'ir''is''it''je''jm''jo''jp''ke''kg''kh',
  62.         'ki''km''kn''kp''kr''kw''ky''kz''la''lb',
  63.         'lc''li''lk''lr''ls''lt''lu''lv''ly''ma',
  64.         'mc''md''me''mf''mg''mh''mk''ml''mm''mn',
  65.         'mo''mp''mq''mr''ms''mt''mu''mv''mw''mx',
  66.         'my''mz''na''nc''ne''nf''ng''ni''nl''no',
  67.         'np''nr''nu''nz''om''pa''pe''pf''pg''ph',
  68.         'pk''pl''pm''pn''pr''ps''pt''pw''py''qa',
  69.         're''ro''rs''ru''rw''sa''sb''sc''sd''se',
  70.         'sg''sh''si''sj''sk''sl''sm''sn''so''sr',
  71.         'ss''st''su''sv''sx''sy''sz''tc''td''tf',
  72.         'tg''th''tj''tk''tl''tm''tn''to''tp''tr',
  73.         'tt''tv''tw''tz''ua''ug''uk''um''us''uy',
  74.         'uz''va''vc''ve''vg''vi''vn''vu''wf''ws',
  75.         'ye''yt''za''zm''zw''한국''中国''中國',
  76.         '香港''台湾''台灣''新加坡''テスト',
  77.     );
  78.     /**#@-*/
  79.     // }}}
  80.  
  81.     // {{{ (string) public MTA_Generate::boundary (void)
  82.     /**
  83.      * mail boundary 생성
  84.      *
  85.      * @access public
  86.      * @return string boundary 문자열
  87.      */
  88.     public function boundary ({
  89.         $uc uniqid ();
  90.         $one strtoupper ($uc[3$uc[1]$uc[0]);
  91.         $two substr ($uc18);
  92.         $three substr ($uc-8);
  93.  
  94.         return sprintf (
  95.             "--=_NextPart_000_0%s_%s.%s",
  96.             $one$two$three
  97.         );
  98.     }
  99.     // }}}
  100.  
  101.     // {{{ (string) public MTA_Generate::msgid (void)
  102.     /**
  103.      * Message ID 생성
  104.      *
  105.      * @access public
  106.      * @return string Message-ID
  107.      */
  108.     public function msgid ({
  109.         return '<' date ('YmdHis'rand ('@' gethostname ('>';
  110.     }
  111.     // }}}
  112.  
  113.     // {{{ (string) public MTA_Generate::date (void)
  114.     /**
  115.      * 메일 헤더에서 사용할 시간 형식 반환
  116.      *
  117.      * @access public
  118.      * @return string Wed, 8 Jun 2013 05:32:11 +900
  119.      */
  120.     public function date ({
  121.         return date ('D, d M Y H:i:s O');
  122.     }
  123.     // }}}
  124.  
  125.     // {{{ (string) public MTA_Generate::encode ($msg, $split = false)
  126.     /**
  127.      * 메시지 인코딩
  128.      *
  129.      * $split이 false(기본값)로 설정될 경우 다음의 형식으로 반환
  130.      *   =?UTF-8?B?BASE64_문자열?=
  131.      *
  132.      * $split이 true로 설정될 경우, 76컬럼에서 line-break된
  133.      * base64 문자열 반환 (메일 본문 또는 첨부파일 인코딩)
  134.      *
  135.      * @access public
  136.      * @return string 
  137.      * @param string $msg 
  138.      * @param bool $split (optional) true로 설정이 되면 76칼럼에서 line-break된
  139.      *                     base64 문자열을 반환한다.
  140.      */
  141.     public function encode ($msg$split false{
  142.         if $split )
  143.             return chunk_split (base64_encode ($msg)76"\r\n");
  144.  
  145.         return '=?UTF-8?B?' base64_encode ($msg'?=';
  146.     }
  147.     // }}}
  148.  
  149.     // {{{ public MTA_Generate::addr (&$addr)
  150.     /**
  151.      * Check mail address and convert email format
  152.      *
  153.      * @access private
  154.      * @return bool 에러 발생시, myException으로 에러 메시지를 보낸다.
  155.      * @param  string &$addr 검사할 메일 주소. 지원 형식은 다음과 같다.
  156.      *                     - user@domain.com
  157.      *                     - <user@domain.com>
  158.      *                     - 이름 <user@domain.com>
  159.      */
  160.     public function addr (&$addr{
  161.         $addr trim ($addr);
  162.  
  163.         if preg_match ('/^([^<]+)<([^@]+)@([^>]+)>$/'$addr$matches) ) {
  164.             $e = (object) array (
  165.                 'name' => preg_replace ('/^[\'"]|[\'"]$/'''trim ($matches[1])),
  166.                 'user' => ltrim ($matches[2]),
  167.                 'domain' => rtrim ($matches[3])
  168.             );
  169.         else if preg_match ('/^<?([^@<]+)@([^>]+)>?$/'$addr$matches) ) {
  170.             $e = (object) array (
  171.                 'name' => '',
  172.                 'user' => ltrim ($matches[1]),
  173.                 'domain' => rtrim ($matches[2])
  174.             );
  175.         else {
  176.             if strlen ($addr) )
  177.                 $this->error ('Given address is NULL'E_USER_ERROR);
  178.  
  179.             $this->error ('Invalid email address format'E_USER_ERROR);
  180.         }
  181.  
  182.         if $e->name {
  183.             $e->name '"' $e->name '"';
  184.             if preg_match ('/[^a-z0-9"\'|:;{}\[\]()!#$%&*+_=~., -]/i'$e->name) )
  185.                 $e->name $this->encode ($e->name);
  186.             $e->name .= ' ';
  187.         }
  188.  
  189.         $this->check_local ($e->user);
  190.         $this->check_domain ($e->domain);
  191.  
  192.         $addr sprintf ('%s<%s@%s>'$e->nametrim ($e->user)($e->domain));
  193.  
  194.         return true;
  195.     }
  196.     // }}}
  197.  
  198.     // {{{ (bool) protected MTA_Generate::check_local ($user, $method = false)
  199.     /**
  200.      * 메일 주소의 local 섹션의 유효성을 검증한다.
  201.      *
  202.      * @access protected
  203.      * @return bool 에러 발생시에, myException으로 에러를 보낸다.
  204.      * @param  string $user 검사할 메일 주소의 local 섹션값
  205.      * @param  bool   $method (optional) true로 설정하면, 에러 발생시에 false를 반환
  206.      */
  207.     protected function check_local ($user$method false{
  208.         if $user[0== '"' && $user[strlen ($user1== '"' {
  209.             $src array ('/[ ]/''/^"|"$/');
  210.             $dst array ('+++blank+++''');
  211.             $user preg_replace ($src$dst$user);
  212.         }
  213.  
  214.         // UTF-8 한글 영역 추가
  215.         if preg_match ('/[^\x{1100}-\x{11FF}\x{3130}-\x{318F}\x{AC00}-\x{D7AF}a-z0-9.+_]/ui'$user) ) {
  216.             if $method )
  217.                 return false;
  218.  
  219.             $this->error ('Invalid local part of email address'E_USER_WARNING);
  220.         }
  221.  
  222.         return true;
  223.     }
  224.     // }}}
  225.  
  226.     // {{{ (bool) protected MTA_Generate::check_domain ($domain, $method = false)
  227.     /**
  228.      * Check domain of mail address
  229.      * 메일 주소의 도메인 섹션의 유효성을 검증한다.
  230.      *
  231.      * @access protected
  232.      * @return bool 
  233.      * @param  string $domain 검사할 메일 주소의 도메인 섹션
  234.      * @param  bool   $method (optional) true로 설정하면, 에러 발생시에 false를 반환
  235.      */
  236.     protected function check_domain ($domain$method false{
  237.         $domlen strlen ($domain);
  238.  
  239.         if $domlen 253 )
  240.             $this->error ('Invalid length of domain part (max 253)'E_USER_ERROR);
  241.  
  242.         // If domain part don't have dot character,
  243.         // permit only top-level domain or local hostname
  244.         if preg_match ('/\./'$domain ) ) {
  245.             if array_search ($domain$this->gTLD!== false )
  246.                 return true;
  247.  
  248.             if array_search ($domain$this->ccTLD!== false )
  249.                 return true;
  250.  
  251.             if gethostbyname ($domain!== false )
  252.                 return true;
  253.  
  254.             if $this->method {
  255.                 $this->error (
  256.                     sprintf ('%s is not gTLD or ccTLD or local hostname'$domain),
  257.                     E_USER_ERROR
  258.                 );
  259.             }
  260.  
  261.             return false;
  262.         }
  263.  
  264.         // check IPv4 or IPv6 format
  265.         if $domain[0== '[' && $domain[$domlen 1== ']' {
  266.             // check for IPv4
  267.             if preg_match (
  268.                     '/^\[([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\]$/',
  269.                     $domain$matches
  270.                 )
  271.             {
  272.                 foreach ($matches as $key => $val {
  273.                     if $key == )
  274.                         continue;
  275.  
  276.                     if $val 255 {
  277.                         if $this->method {
  278.                             $this->error (
  279.                                 sprintf ('%s is not invalid IPv4 format'$domain),
  280.                                 E_USER_ERROR
  281.                             );
  282.                         }
  283.  
  284.                         return false;
  285.                     }
  286.                 }
  287.  
  288.                 return true;
  289.             }
  290.  
  291.             // check for IPv6
  292.             if preg_match ('/^\[IPV6:[0-9a-z:]+\]$/'$domain) )
  293.                 return true;
  294.  
  295.             if $this->method {
  296.                 $this->error (
  297.                     sprintf ('%s is invliad email address format'$domain),
  298.                     E_USER_ERROR
  299.                 );
  300.             }
  301.  
  302.             return false;
  303.         }
  304.  
  305.         // check General domain format
  306.         if preg_match ('/\.\.+/'$domain) ) {
  307.             if $this->method )
  308.                 $this->error ('Invalid domain part'E_USER_ERROR);
  309.  
  310.             return false;
  311.         }
  312.  
  313.         $tld preg_replace ('/.*\.([^.]+)$/''\\1'$domain);
  314.  
  315.         if array_search ($tld$this->gTLD=== false &&
  316.             array_search ($tld$this->ccTLD=== false {
  317.  
  318.             if $this->method )
  319.                 $this->error ('Invliad TLD'E_USER_ERROR);
  320.  
  321.             return false;
  322.         }
  323.  
  324.         return true;
  325.     }
  326.     // }}}
  327.  
  328.     // {{{ (string) public MTA_Generate::mime ($path)
  329.     /**
  330.      * 파일 확장자에 대한 mime type을 반환
  331.      *
  332.      * fileinfo extension이 제공되면 fileinfo api를 사용하며,
  333.      * 지원하지 않을경우 자체 정의된 mime-type을 반환한다.
  334.      *
  335.      * @access public
  336.      * @return string 
  337.      * @param string $path 검사할 파일 경로
  338.      */
  339.     public function mime ($path{
  340.         if function_exists ('finfo_open') ) {
  341.             $fi finfo_open (FILEINFO_MIME_TYPE);
  342.             $mime finfo_file ($fi$path);
  343.             finfo_close ($fi);
  344.  
  345.             return $mime;
  346.         }
  347.  
  348.         if preg_match ('^/.+\.([^.]+)$/'$path$matches) ) {
  349.             $path $matches[1];
  350.         else
  351.             return 'application/octet-stream';
  352.  
  353.         if $path == 'ez'  return 'application/andrew-inset';
  354.         else if $path == 'hqx' return 'application/mac-binhex40';
  355.         else if $path == 'cpt' return 'application/mac-compactpro';
  356.         else if $path == 'doc' return 'application/msword';
  357.         else if $path == 'oda' return 'application/oda';
  358.         else if $path == 'pdf' return 'application/pdf';
  359.         else if $path == 'rtf' return 'application/rtf';
  360.         else if $path == 'mif' return 'application/vnd.mif';
  361.         else if $path == 'ppt' return 'application/vnd.ms-powerpoint';
  362.         else if $path == 'slc' return 'application/vnd.wap.slc';
  363.         else if $path == 'sic' return 'application/vnd.wap.sic';
  364.         else if $path == 'wmlc' return 'application/vnd.wap.wmlc';
  365.         else if $path == 'wmlsc' return 'application/vnd.wap.wmlscriptc';
  366.         else if $path == 'bcpio' return 'application/x-bcpio';
  367.         else if $path == 'bz2' return 'application/x-bzip2';
  368.         else if $path == 'vcd' return 'application/x-cdlink';
  369.         else if $path == 'pgn' return 'application/x-chess-pgn';
  370.         else if $path == 'cpio' return 'application/x-cpio';
  371.         else if $path == 'csh' return 'application/x-csh';
  372.         else if $path == 'dvi' return 'application/x-dvi';
  373.         else if $path == 'spl' return 'application/x-futuresplash';
  374.         else if $path == 'gtar' return 'application/x-gtar';
  375.         else if $path == 'hdf' return 'application/x-hdf';
  376.         else if $path == 'js' return 'application/x-javascript';
  377.         else if $path == 'ksp' return 'application/x-kspread';
  378.         else if $path == 'kpr' || $path == 'kpt' return 'application/x-kpresenter';
  379.         else if $path == 'chrt' return 'application/x-kchart';
  380.         else if $path == 'kil' return 'application/x-killustrator';
  381.         else if $path == 'skp' || $path == 'skd' || $path == 'skt' || $path == 'skm' )
  382.             return 'application/x-koan';
  383.         else if $path == 'latex' return 'application/x-latex';
  384.         else if $path == 'nc' || $path == 'cdf' return 'application/x-netcdf';
  385.         else if $path == 'rpm' return 'application/x-rpm';
  386.         else if $path == 'sh' return 'application/x-sh';
  387.         else if $path == 'shar' return 'application/x-shar';
  388.         else if $path == 'swf' return 'application/x-shockwave-flash';
  389.         else if $path == 'sit' return 'application/x-stuffit';
  390.         else if $path == 'sv4cpio' return 'application/x-sv4cpio';
  391.         else if $path == 'sv4crc' return 'application/x-sv4crc';
  392.         else if $path == 'tar' return 'application/x-tar';
  393.         else if $path == 'tcl' return 'application/x-tcl';
  394.         else if $path == 'tex' return 'application/x-tex';
  395.         else if $path == 'texinfo' || $path == 'texi' return 'application/x-texinfo';
  396.         else if $path == 't' || $path == 'tr' || $path == 'roff' )
  397.             return 'application/x-troff';
  398.         else if $path == 'man' return 'application/x-troff-man';
  399.         else if $path == 'me' return 'application/x-troff-me';
  400.         else if $path == 'ms' return 'application/x-troff-ms';
  401.         else if $path == 'ustar' return 'application/x-ustar';
  402.         else if $path == 'src' return 'application/x-wais-source';
  403.         else if $path == 'zip' return 'application/zip';
  404.         else if $path == 'gif' return 'image/gif';
  405.         else if $path == 'ief' return 'image/ief';
  406.         else if $path == 'wbmp' return 'image/vnd.wap.wbmp';
  407.         else if $path == 'ras' return 'image/x-cmu-raster';
  408.         else if $path == 'pnm' return 'image/x-portable-anymap';
  409.         else if $path == 'pbm' return 'image/x-portable-bitmap';
  410.         else if $path == 'pgm' return 'image/x-portable-graymap';
  411.         else if $path == 'ppm' return 'image/x-portable-pixmap';
  412.         else if $path == 'rgb' return 'image/x-rgb';
  413.         else if $path == 'xbm' return 'image/x-xbitmap';
  414.         else if $path == 'xpm' return 'image/x-xpixmap';
  415.         else if $path == 'xwd' return 'image/x-xwindowdump';
  416.         else if $path == 'css' return 't$path/css';
  417.         else if $path == 'rtx' return 't$path/richt$path';
  418.         else if $path == 'rtf' return 't$path/rtf';
  419.         else if $path == 'tsv' return 't$path/tab-separated-values';
  420.         else if $path == 'sl' return 't$path/vnd.wap.sl';
  421.         else if $path == 'si' return 't$path/vnd.wap.si';
  422.         else if $path == 'wml' return 't$path/vnd.wap.wml';
  423.         else if $path == 'wmls' return 't$path/vnd.wap.wmlscript';
  424.         else if $path == 'etx' return 't$path/x-set$path';
  425.         else if $path == 'xml' return 't$path/xml';
  426.         else if $path == 'avi' return 'video/x-msvideo';
  427.         else if $path == 'movie' return 'video/x-sgi-movie';
  428.         else if $path == 'wma' return 'audio/x-ms-wma';
  429.         else if $path == 'wax' return 'audio/x-ms-wax';
  430.         else if $path == 'wmv' return 'video/x-ms-wmv';
  431.         else if $path == 'wvx' return 'video/x-ms-wvx';
  432.         else if $path == 'wm' return 'video/x-ms-wm';
  433.         else if $path == 'wmx' return 'video/x-ms-wmx';
  434.         else if $path == 'wmz' return 'application/x-ms-wmz';
  435.         else if $path == 'wmd' return 'application/x-ms-wmd';
  436.         else if $path == 'ice' return 'x-conference/x-cooltalk';
  437.         else if $path == 'ra' return 'audio/x-realaudio';
  438.         else if $path == 'wav' return 'audio/x-wav';
  439.         else if $path == 'png' return 'image/png';
  440.         else if $path == 'asf' || $path == 'asx' return 'video/x-ms-asf';
  441.         else if $path == 'html' || $path == 'htm' return 't$path/html';
  442.         else if $path == 'smi' || $path == 'smil' return 'application/smil';
  443.         else if $path == 'gz' || $path == 'tgz' return 'application/x-gzip';
  444.         else if $path == 'kwd' || $path == 'kwt' return 'application/x-kword';
  445.         else if $path == 'kpr' || $path == 'kpt' return 'application/x-kpresenter';
  446.         else if $path == 'au' || $path == 'snd' return 'audio/basic';
  447.         else if $path == 'ram' || $path == 'rm' return 'audio/x-pn-realaudio';
  448.         else if $path == 'pdb' || $path == 'xyz' return 'chemical/x-pdb';
  449.         else if $path == 'tiff' || $path == 'tif' return 'image/tiff';
  450.         else if $path == 'igs' || $path == 'iges' return 'model/iges';
  451.         else if $path == 'wrl' || $path == 'vrml' return 'model/vrml';
  452.         else if $path == 'asc' || $path == 'txt' || $path == 'php' return 't$path/plain';
  453.         else if $path == 'sgml' || $path == 'sgm' return 't$path/sgml';
  454.         else if $path == 'qt' || $path == 'mov' return 'video/quicktime';
  455.         else if $path == 'ai' || $path == 'eps' || $path == 'ps' return 'application/postscript';
  456.         else if $path == 'dcr' || $path == 'dir' || $path == 'dxr' return 'application/x-director';
  457.         else if $path == 'mid' || $path == 'midi' || $path == 'kar' return 'audio/midi';
  458.         else if $path == 'mpga' || $path == 'mp2' || $path == 'mp3' return 'audio/mpeg';
  459.         else if $path == 'aif' || $path == 'aiff' || $path == 'aifc' return 'audio/x-aiff';
  460.         else if $path == 'jpeg' || $path == 'jpg' || $path == 'jpe' return 'image/jpeg';
  461.         else if $path == 'msh' || $path == 'mesh' || $path == 'silo' return 'model/mesh';
  462.         else if $path == 'mpeg' || $path == 'mpg' || $path == 'mpe' return 'video/mpeg';
  463.         else return 'application/octet-stream';
  464.     }
  465.     // }}}
  466.  
  467.     // {{{ (string) public MTA_Generate::attach ($attaches, $bound)
  468.     /**
  469.      * Attach file의 template을 생성
  470.      *
  471.      * @access public
  472.      * @return string 
  473.      * @param array $attaches 파일 경로를 포함한 배열
  474.      * @param string $bound boundary 문자열
  475.      */
  476.     public function attach ($attaches$bound{
  477.         if is_array ($attaches) )
  478.             return '';
  479.  
  480.         if count ($attaches== )
  481.             return '';
  482.  
  483.         foreach $attaches as $path {
  484.             if file_exists ($path|| is_readable ($path) )
  485.                 continue;
  486.  
  487.             $mime $this->mime ($path);
  488.             $fname basename ($path);
  489.  
  490.             $pos preg_match ('/^image\//'$mime?  'inline' 'attachment';
  491.  
  492.             $buf .=
  493.                 '--' $bound "\r\n" .
  494.                 "Content-Type: {$mime}; name=\"{$fname}\"\r\n.
  495.                 "Content-Transfer-Encoding: base64\r\n" .
  496.                 "Content-Disposition: inline; filename=\"{$fname}\"\r\n\r\n.
  497.                 $this->encode (file_get_contents ($path)true"\r\n";
  498.         }
  499.  
  500.         return $buf;
  501.     }
  502.     // }}}
  503.  
  504.     // {{{ (void) protected MTA_Generate::error ($msg, $level)
  505.     /**
  506.      * 에러 발생시에, 에러 메시지를 myException으로 전달한다.
  507.      *
  508.      * @access protected
  509.      * @return void 
  510.      * @param  string $msg   exception message
  511.      * @param  int    $level exception error level
  512.      */
  513.     protected function error ($msg$level{
  514.         throw new myException ($msg$level);
  515.     }
  516.     // }}}
  517. }
  518.  
  519. /*
  520.  * Local variables:
  521.  * tab-width: 4
  522.  * c-basic-offset: 4
  523.  * End:
  524.  * vim: set filetype=php noet sw=4 ts=4 fdm=marker:
  525.  * vim600: noet sw=4 ts=4 fdm=marker
  526.  * vim<600: noet sw=4 ts=4
  527.  */
  528. ?>

Documentation generated on Tue, 14 May 2019 02:00:34 +0900 by phpDocumentor 1.4.4