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

Source for file WebAPI_Autolink.php

Documentation is available at WebAPI_Autolink.php

  1. <?php
  2. /**
  3.  * Project: WebAPI_Autolink :: Auto link API
  4.  * File:    WebAPI/WebAPI_Autolink.php
  5.  *
  6.  * WebAPI_Autolink class는 문맥속의 URL을 hyper link로 만들어
  7.  * 준다.
  8.  *
  9.  * @category    HTTP
  10.  * @package     WebAPI
  11.  * @subpackage  WebAPI_Autolink
  12.  * @author      JoungKyun.Kim <http://oops.org>
  13.  * @copyright   (c) 2018, OOPS.org
  14.  * @license     BSD License
  15.  * @link        http://pear.oops.org/package/WebAPI
  16.  * @filesource
  17.  * @since       0.0.1
  18.  */
  19.  
  20. /**
  21.  * Autolink API for WebAPI Package
  22.  *
  23.  * WebAPI_Autolink class는 문맥속의 URL을 hyper link로 변경
  24.  *
  25.  * @package     WebAPI
  26.  */
  27. Class WebAPI_Autolink {
  28.     // {{{ properties
  29.     /**#@+
  30.      * @access private
  31.      */
  32.     static private $reg_charset array (
  33.         //'uhan' => '\x{1100}-\x{11FF}\x{3130}-\x{318F}\x{AC00}-\x{D7AF}',
  34.         'uhan' => '\p{Hangul}\p{Han}\p{Hiragana}\p{Katakana}',
  35.         'ehan' => '\xA1-\xFE',
  36.     );
  37.     static private $reg null;
  38.     /**#@-*/
  39.  
  40.     /**
  41.      * UTF-8 모드 사용 여부. 기본값 true
  42.      *
  43.      * @access public
  44.      * @var bool 
  45.      */
  46.     static public $utf8 = true;
  47.     // }}}
  48.  
  49.     // {{{ +-- private (void) set_regex_template (void)
  50.     /**
  51.      * WebStirng_Autolink class에서 사용할 template 초기화
  52.      *
  53.      * @access public
  54.      * @return void 
  55.      */
  56.     private function set_regex_template ({
  57.         if self::$reg !== null )
  58.             return;
  59.  
  60.         $ext 'gz|tgz|tar|gzip|zip|rar|mpeg|mpg|exe|rpm|dep|rm|ram|asf' .
  61.                 '|ace|viv|avi|mid|gif|jpg|png|bmp|eps|mov';
  62.  
  63.         $han self::$utf8 self::$reg_charset['uhan'self::$reg_charset['han'];
  64.  
  65.         self::$reg = (object) array (
  66.             'file' => '(\.(' $ext ')") target="_blank"',
  67.             'link' => "(https?|s?ftp|telnet|news|mms):\/\/(([{$han}a-z0-9:_\-]+\.[{$han}a-z0-9,:;&#=_~%\[\]?\/.,+\-]+)([.]*[\/a-z0-9\[\]]|=[{$han}]+))",
  68.             'mail' => "([{$han}a-z0-9+_.-]+)@([{$han}a-z0-9_-]+\.[{$han}a-z0-9._-]*[a-z]{2,3}(\?[\s{$han}a-z0-9=&\?;%]+|%[0-9]{2})*)"
  69.         );
  70.     }
  71.     // }}}
  72.  
  73.     // {{{ +-- static private (void) nomalize (&$v)
  74.     /**
  75.      * autolink를 하기 전에 autolink와 관련된 사항을 nomalize 한다.
  76.      *
  77.      *   - 개행 문자를 \n으로 통일
  78.      *   - IMG, A tag를 한줄로 만듬
  79.      *   - style, src, codebase, pluginspace, background tag property을
  80.      *     한줄로 만듬
  81.      *   - link의 target과 javascript event를 제거
  82.      */
  83.     private function nomalize (&$v{
  84.         $v preg_replace ("/\r?\n/""\n"$v);
  85.         $um self::$utf8 'u' '';
  86.  
  87.         $src array (
  88.             '/<[\s]*(a|img)[\s]*[^>]+>/i',
  89.             '/(style|action|src|codebase|pluginspace|background)[\s]*=[\s]*[\'\"][^\'"]+[\'"]/i'
  90.         );
  91.  
  92.         $v preg_replace_callback (
  93.             $src,
  94.             function ($matches{
  95.                 $src['/[\s]+/';
  96.                 $des[' ';
  97.                 $src['/[\s]*=[\s]*/';
  98.                 $des['=';
  99.                 $src['/=[\'"][\s]*([^\'"]+)[\s]+[\'"]/';
  100.                 $des['="\\1"';
  101.                 $src['/[\s]*(target|on[a-z]+)=[^\s>]+/i';
  102.                 $des['';
  103.                 $src['/<[\s]+/';
  104.                 $des['<';
  105.                 $src['/[\s]+>/';
  106.                 $des['>';
  107.                 return preg_replace ($src$des$matches[0]);
  108.             },
  109.             $v
  110.         );
  111.  
  112.         $han self::$utf8 self::$reg_charset['uhan'self::$reg_charset['han'];
  113.  
  114.         // URL 내의 공백문자 처리
  115.         $src array (
  116.             "!((https?|s?ftp|telnet|news|mms)://[^</]+)(/[^</]+/)!im",
  117.             "!((https?|s?ftp|telnet|news|mms)://.*/)([{$han}a-z0-9,_-]+[\s]+[[{$han}a-z0-9,_-]*\.(jpg|png|gif|psd|txt|html?|(doc|xls|ppt)x?))!{$um}im",
  118.         );
  119.         $v preg_replace_callback (
  120.             $src,
  121.             function ($matches{
  122.                 $org trim ($matches[3]);
  123.                 if ($len strlen ($org)) )
  124.                     return '';
  125.  
  126.                 $new '';
  127.                 for $i=0$i<$len$i++ {
  128.                     if $org[$i== ' ' || $org[$i== "\t" )
  129.                         $new .= '%20';
  130.                     else
  131.                         $new .= $org[$i];
  132.                 }
  133.                 return $matches[1$new;
  134.             },
  135.             $v
  136.         );
  137.     }
  138.     // }}}
  139.  
  140.     // {{{ +-- static public (void) execute (&$v)
  141.     /**
  142.      * 주어진 문장속의 URL을 hyper link로 변경
  143.      *
  144.      * @access public
  145.      * @return string 
  146.      * @param string 문자열
  147.      */
  148.     static public function execute (&$v{
  149.         self::set_regex_template ();
  150.         $reg &self::$reg;
  151.  
  152.         $um self::$utf8 'u' '';
  153.  
  154.         self::nomalize ($v);
  155.  
  156.         # Tag nomalizing -> self::nomalize 로 이동..
  157.         # 아래는 기존의 nomalize 임!
  158.         #
  159.         # &lt; 로 시작해서 3줄뒤에 &gt; 가 나올 경우와
  160.         # IMG tag 와 A tag 의 경우 링크가 여러줄에 걸쳐 이루어져 있을 경우
  161.         # 이를 한줄로 합침 (합치면서 부가 옵션들은 모두 삭제함)
  162.         #$src[] = "/<([^<>\n]*)\n([^<>\n]+)\n([^<>\n]*)>/i";
  163.         #$des[] = '<\\1\\2\\3>';
  164.         #$src[] = "/<([^<>\n]*)\n([^\n<>]*)>/i";
  165.         #$des[] = '<\\1\\2>';
  166.         #$src[] = "/<(A|IMG)[^>]*(href|src)[^=]*=['\"\s]*({$reg->link}|mailto:{$reg->mail})[^>]*>/{$um}i";
  167.         #$des[] = '<\\1 \\2="\\3">';
  168.  
  169.         # email 형식이나 URL 에 포함될 경우 URL 보호를 위해 @ 을 치환
  170.         $src["/(http|https|ftp|telnet|news|mms):\/\/([^\s@]+)@/i";
  171.         $des['\\1://\\2_HTTPAT_\\3';
  172.  
  173.         # 특수 문자를 치환 및 html사용시 link 보호
  174.         $src['/&(quot|gt|lt)/i';
  175.         $des['!\\1';
  176.         $src["/<a([^>]*)href=[\"'\s]*({$reg->link})[\"']*[^>]*>/{$um}i";
  177.         $des['<a\\1href="\\3_orig://\\4" target="_blank">';
  178.         $src["/href=[\"'\s]*mailto:({$reg->mail})[\"']*>/{$um}i";
  179.         $des['href="mailto:\\2#-#\\3">';
  180.         # 1 라인에 중복 되어 있을 수 있으므로 중복되어 사용되지 않는
  181.         # 태크들로 나누어 준다.
  182.         $src["/<([^>]*)(background|src|action)[\s]*=[\"'\s]*({$reg->link})[\"']*/${um}i";
  183.         $des['<\\1\\2="\\4_orig://\\5"';
  184.         $src["/<([^>]*)(codebase|pluginspage|value)[\s]*=[\"'\s]*({$reg->link})[\"']*/${um}i";
  185.         $des['<\\1\\2="\\4_orig://\\5"';
  186.         $src["/<([^>]*)(rsrc)[\s]*=[\"'\s]*({$reg->link})[\"']*/${um}i";
  187.         $des['<\\1\\2="\\4_orig://\\5"';
  188.  
  189.         # 링크가 안된 url및 email address 자동링크
  190.         $src["/((src|href|base|ground)[\s]*=[\s]*|[^=]|^)({$reg->link})/{$um}i";
  191.         $des['\\1<a href="\\3" target="_blank">\\3</a>';
  192.         $src["/({$reg->mail})/{$um}i";
  193.         $des['<a href="mailto:\\1">\\1</a>';
  194.         $src['/<a href=[^>]+>(<a href=[^>]+>)/i';
  195.         $des['\\1';
  196.         $src['/<\/a><\/a>/i';
  197.         $des['</a>';
  198.  
  199.         # 보호를 위해 치환한 것들을 복구
  200.         $src['/!(quot|gt|lt)/i';
  201.         $des['&\\1';
  202.         $src['/(http|https|ftp|telnet|news|mms)_orig/i';
  203.         $des['\\1';
  204.         $src['/#-#/';
  205.         $des['@';
  206.         $src["/{$reg->file}/${um}i";
  207.         $des['\\1';
  208.  
  209.         # email 주소를 변형시킴
  210.         $src["/mailto:[\s]*{$reg->mail}/${um}i";
  211.         $des['javascript:location.href=\'mailto:\\1\' + \'@\' + \'\\2\';';
  212.         $src["/{$reg->mail}/${um}i";
  213.         $des['\\1&#0064;\\2'// @ html entity
  214.         $src['/<</';
  215.         $des['&lt;<';
  216.         $src['/>>/';
  217.         $des['>&gt;';
  218.  
  219.         # email 주소를 변형한 뒤 URL 속의 @ 을 복구
  220.         $src['/_HTTPAT_/';
  221.         $des['@';
  222.  
  223.         $v preg_replace ($src$des$v);
  224.     }
  225.     // }}}
  226.  
  227.     // {{{ +-- static public (boolean) is_email ($v)
  228.     /**
  229.      * 주어진 이메일이 valid한지 확인.
  230.      *
  231.      * 도메인 파트의 경우 MX record가 있거나 또는 inverse domain이 설정되어 있어야
  232.      * true로 판별한다. 도메인 파트가 IP주소일 경우에는 MX record나 inverse domain
  233.      * 을 체크하지 않는다.
  234.      *
  235.      * 다음의 형식을 체크한다.
  236.      *
  237.      *     - id@domain.com
  238.      *     - id@[IPv4]
  239.      *     - name <id@domain.com>
  240.      *     - id@domain.com?subject=title&cc=...
  241.      *     - name <id@domain.com?subject=title&cc=...>
  242.      *
  243.      * 이메일 parameter가 존재할 경우에는, CC, BCC, SUBJECT, BODY 만 허가가 된다. 만약,
  244.      * 이메일 parameter를 체크하고 싶지 않다면, 이 method에 넘기는 값에서 parameter를
  245.      * 제거하고 넘겨야 한다.
  246.      *
  247.      * @access public
  248.      * @return boolean 
  249.      * @param string check email address
  250.      */
  251.     static public function is_email ($v{
  252.         self::set_regex_template ();
  253.  
  254.         $v trim ($v);
  255.  
  256.         // check format "name" <id@domain.com>
  257.         if preg_match ('/^[^<]+[\s]*<([^@]+@[^>]+)>$/'$v$m) )
  258.             $v $m[1];
  259.  
  260.         // check sub strings
  261.         $m preg_split ('/\?/'$v);
  262.         if count ($m{
  263.             if self::is_email ($m[0]=== false )
  264.                 return false;
  265.  
  266.             parse_str (substr (strstr ($v'?')1)$sub);
  267.             $v $m[0];
  268.  
  269.             // allow CC, BCC, BODY, SUBJECT
  270.             foreach $sub as $key => $val {
  271.                 $key strtolower ($key);
  272.                 switch ($key{
  273.                     case 'cc' :
  274.                     case 'bcc' :
  275.                         $emails preg_split ('/,/'$val);
  276.                         foreach $emails as $email {
  277.                             if self::is_email (trim ($email)) === false )
  278.                                 return false;
  279.                         }
  280.                         break;
  281.                     case 'body' :
  282.                     case 'subject' :
  283.                         break;
  284.                     default :
  285.                         return false;
  286.                 }
  287.             }
  288.         }
  289.  
  290.         // check id@[1.1.1.1]
  291.         $ip false;
  292.         if preg_match ('/^([^@]+)@\[([0-9.]+)\]$/'$v$m) ) {
  293.             $lv sprintf ('%lu'ip2long ($m[2]));
  294.             if $lv || $lv 16777216 )
  295.                 return false;
  296.             $ip true;
  297.             $v $m[1'@google.com';
  298.         }
  299.  
  300.         if preg_match ('/^' self::$reg->mail '$/i'$v) )
  301.             return false;
  302.  
  303.         if $ip === true )
  304.             return true;
  305.  
  306.         // email의 도메인이 MX record가 있거나 inverse domain
  307.         // 셋팅이 되어 있어야 valid 처리한다.
  308.         list ($user$hostpreg_split ('/@/'$v);
  309.         if checkdnsrr ($host'MX'|| gethostbynamel ($host) )
  310.             return true;
  311.  
  312.         return false;
  313.     }
  314.     // }}}
  315.  
  316.     // {{{ +-- static public (boolean) is_url (&$v)
  317.     /**
  318.      * 주어진 url이 valid한지 확인
  319.      *
  320.      * @access public
  321.      * @return boolean 
  322.      * @param string check email address
  323.      */
  324.     static public function is_url (&$v{
  325.         if self::is_protocol ($v) )
  326.             return false;
  327.  
  328.         if preg_match ('/^' self::$reg->link '$/i'$v) )
  329.             return true;
  330.  
  331.         return false;
  332.     }
  333.     // }}}
  334.  
  335.     // {{{ +-- static public (boolean) is_protocol (&$v)
  336.     /**
  337.      * 주어진 protocol이 valid한지 확인
  338.      *
  339.      * @access public
  340.      * @return boolean 
  341.      * @param string check email address
  342.      */
  343.     static public function is_protocol (&$v{
  344.         if preg_match ('!^(http[s]?|ftp[s]?|telnet|news|mms)://!i'$v) )
  345.             return false;
  346.         return true;
  347.     }
  348.     // }}}
  349. }
  350.  
  351. /*
  352.  * Local variables:
  353.  * tab-width: 4
  354.  * c-basic-offset: 4
  355.  * End:
  356.  * vim: set filetype=php noet sw=4 ts=4 fdm=marker:
  357.  * vim600: noet sw=4 ts=4 fdm=marker
  358.  * vim<600: noet sw=4 ts=4
  359.  */
  360. ?>

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