Grammar.php 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <?php
  2. /*
  3. * This file is part of SwiftMailer.
  4. * (c) 2004-2009 Chris Corbyn
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * Defines the grammar to use for validation, implements the RFC 2822 (and friends) ABNF grammar definitions.
  11. * @package Swift
  12. * @subpackage Mime
  13. * @author Fabien Potencier
  14. * @author Chris Corbyn
  15. */
  16. class Swift_Mime_Grammar
  17. {
  18. /**
  19. * Special characters used in the syntax which need to be escaped.
  20. * @var string[]
  21. * @access private
  22. */
  23. private $_specials = array();
  24. /**
  25. * Tokens defined in RFC 2822 (and some related RFCs).
  26. * @var string[]
  27. * @access private
  28. */
  29. private $_grammar = array();
  30. /**
  31. * Initialize some RFC 2822 (and friends) ABNF grammar definitions.
  32. * @access protected
  33. */
  34. public function __construct()
  35. {
  36. $this->_specials = array(
  37. '(', ')', '<', '>', '[', ']',
  38. ':', ';', '@', ',', '.', '"'
  39. );
  40. /*** Refer to RFC 2822 for ABNF grammar ***/
  41. //All basic building blocks
  42. $this->_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]';
  43. $this->_grammar['WSP'] = '[ \t]';
  44. $this->_grammar['CRLF'] = '(?:\r\n)';
  45. $this->_grammar['FWS'] = '(?:(?:' . $this->_grammar['WSP'] . '*' .
  46. $this->_grammar['CRLF'] . ')?' . $this->_grammar['WSP'] . ')';
  47. $this->_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]';
  48. $this->_grammar['quoted-pair'] = '(?:\\\\' . $this->_grammar['text'] . ')';
  49. $this->_grammar['ctext'] = '(?:' . $this->_grammar['NO-WS-CTL'] .
  50. '|[\x21-\x27\x2A-\x5B\x5D-\x7E])';
  51. //Uses recursive PCRE (?1) -- could be a weak point??
  52. $this->_grammar['ccontent'] = '(?:' . $this->_grammar['ctext'] . '|' .
  53. $this->_grammar['quoted-pair'] . '|(?1))';
  54. $this->_grammar['comment'] = '(\((?:' . $this->_grammar['FWS'] . '|' .
  55. $this->_grammar['ccontent']. ')*' . $this->_grammar['FWS'] . '?\))';
  56. $this->_grammar['CFWS'] = '(?:(?:' . $this->_grammar['FWS'] . '?' .
  57. $this->_grammar['comment'] . ')*(?:(?:' . $this->_grammar['FWS'] . '?' .
  58. $this->_grammar['comment'] . ')|' . $this->_grammar['FWS'] . '))';
  59. $this->_grammar['qtext'] = '(?:' . $this->_grammar['NO-WS-CTL'] .
  60. '|[\x21\x23-\x5B\x5D-\x7E])';
  61. $this->_grammar['qcontent'] = '(?:' . $this->_grammar['qtext'] . '|' .
  62. $this->_grammar['quoted-pair'] . ')';
  63. $this->_grammar['quoted-string'] = '(?:' . $this->_grammar['CFWS'] . '?"' .
  64. '(' . $this->_grammar['FWS'] . '?' . $this->_grammar['qcontent'] . ')*' .
  65. $this->_grammar['FWS'] . '?"' . $this->_grammar['CFWS'] . '?)';
  66. $this->_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]';
  67. $this->_grammar['atom'] = '(?:' . $this->_grammar['CFWS'] . '?' .
  68. $this->_grammar['atext'] . '+' . $this->_grammar['CFWS'] . '?)';
  69. $this->_grammar['dot-atom-text'] = '(?:' . $this->_grammar['atext'] . '+' .
  70. '(\.' . $this->_grammar['atext'] . '+)*)';
  71. $this->_grammar['dot-atom'] = '(?:' . $this->_grammar['CFWS'] . '?' .
  72. $this->_grammar['dot-atom-text'] . '+' . $this->_grammar['CFWS'] . '?)';
  73. $this->_grammar['word'] = '(?:' . $this->_grammar['atom'] . '|' .
  74. $this->_grammar['quoted-string'] . ')';
  75. $this->_grammar['phrase'] = '(?:' . $this->_grammar['word'] . '+?)';
  76. $this->_grammar['no-fold-quote'] = '(?:"(?:' . $this->_grammar['qtext'] .
  77. '|' . $this->_grammar['quoted-pair'] . ')*")';
  78. $this->_grammar['dtext'] = '(?:' . $this->_grammar['NO-WS-CTL'] .
  79. '|[\x21-\x5A\x5E-\x7E])';
  80. $this->_grammar['no-fold-literal'] = '(?:\[(?:' . $this->_grammar['dtext'] .
  81. '|' . $this->_grammar['quoted-pair'] . ')*\])';
  82. //Message IDs
  83. $this->_grammar['id-left'] = '(?:' . $this->_grammar['dot-atom-text'] . '|' .
  84. $this->_grammar['no-fold-quote'] . ')';
  85. $this->_grammar['id-right'] = '(?:' . $this->_grammar['dot-atom-text'] . '|' .
  86. $this->_grammar['no-fold-literal'] . ')';
  87. //Addresses, mailboxes and paths
  88. $this->_grammar['local-part'] = '(?:' . $this->_grammar['dot-atom'] . '|' .
  89. $this->_grammar['quoted-string'] . ')';
  90. $this->_grammar['dcontent'] = '(?:' . $this->_grammar['dtext'] . '|' .
  91. $this->_grammar['quoted-pair'] . ')';
  92. $this->_grammar['domain-literal'] = '(?:' . $this->_grammar['CFWS'] . '?\[(' .
  93. $this->_grammar['FWS'] . '?' . $this->_grammar['dcontent'] . ')*?' .
  94. $this->_grammar['FWS'] . '?\]' . $this->_grammar['CFWS'] . '?)';
  95. $this->_grammar['domain'] = '(?:' . $this->_grammar['dot-atom'] . '|' .
  96. $this->_grammar['domain-literal'] . ')';
  97. $this->_grammar['addr-spec'] = '(?:' . $this->_grammar['local-part'] . '@' .
  98. $this->_grammar['domain'] . ')';
  99. }
  100. /**
  101. * Get the grammar defined for $name token.
  102. * @param string $name execatly as written in the RFC
  103. * @return string
  104. */
  105. public function getDefinition($name)
  106. {
  107. if (array_key_exists($name, $this->_grammar))
  108. {
  109. return $this->_grammar[$name];
  110. }
  111. else
  112. {
  113. throw new Swift_RfcComplianceException(
  114. "No such grammar '" . $name . "' defined."
  115. );
  116. }
  117. }
  118. /**
  119. * Returns the tokens defined in RFC 2822 (and some related RFCs).
  120. * @return array
  121. */
  122. public function getGrammarDefinitions()
  123. {
  124. return $this->_grammar;
  125. }
  126. /**
  127. * Returns the current special characters used in the syntax which need to be escaped.
  128. * @return array
  129. */
  130. public function getSpecials()
  131. {
  132. return $this->_specials;
  133. }
  134. /**
  135. * Escape special characters in a string (convert to quoted-pairs).
  136. * @param string $token
  137. * @param string[] $include additonal chars to escape
  138. * @param string[] $exclude chars from escaping
  139. * @return string
  140. */
  141. public function escapeSpecials($token, $include = array(),
  142. $exclude = array())
  143. {
  144. foreach (
  145. array_merge(array('\\'), array_diff($this->_specials, $exclude), $include) as $char)
  146. {
  147. $token = str_replace($char, '\\' . $char, $token);
  148. }
  149. return $token;
  150. }
  151. }