PageRenderTime 25ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/applications/client/libraries/Swift/classes/Swift/Mime/Headers/AbstractHeader.php

https://bitbucket.org/amitholkar/zenfile-18-05
PHP | 502 lines | 222 code | 54 blank | 226 comment | 29 complexity | e247da8a468695a59c7e46d87e8ef5a4 MD5 | raw file
  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. * An abstract base MIME Header.
  11. *
  12. * @package Swift
  13. * @subpackage Mime
  14. * @author Chris Corbyn
  15. */
  16. abstract class Swift_Mime_Headers_AbstractHeader implements Swift_Mime_Header
  17. {
  18. /**
  19. * The name of this Header.
  20. *
  21. * @var string
  22. */
  23. private $_name;
  24. /**
  25. * The Grammar used for this Header.
  26. *
  27. * @var Swift_Mime_Grammar
  28. */
  29. private $_grammar;
  30. /**
  31. * The Encoder used to encode this Header.
  32. *
  33. * @var Swift_Encoder
  34. */
  35. private $_encoder;
  36. /**
  37. * The maximum length of a line in the header.
  38. *
  39. * @var int
  40. */
  41. private $_lineLength = 78;
  42. /**
  43. * The language used in this Header.
  44. *
  45. * @var string
  46. */
  47. private $_lang;
  48. /**
  49. * The character set of the text in this Header.
  50. *
  51. * @var string
  52. */
  53. private $_charset = 'utf-8';
  54. /**
  55. * The value of this Header, cached.
  56. *
  57. * @var string
  58. */
  59. private $_cachedValue = null;
  60. /**
  61. * Creates a new Header.
  62. *
  63. * @param Swift_Mime_Grammar $grammar
  64. */
  65. public function __construct(Swift_Mime_Grammar $grammar)
  66. {
  67. $this->setGrammar($grammar);
  68. }
  69. /**
  70. * Set the character set used in this Header.
  71. *
  72. * @param string $charset
  73. */
  74. public function setCharset($charset)
  75. {
  76. $this->clearCachedValueIf($charset != $this->_charset);
  77. $this->_charset = $charset;
  78. if (isset($this->_encoder)) {
  79. $this->_encoder->charsetChanged($charset);
  80. }
  81. }
  82. /**
  83. * Get the character set used in this Header.
  84. *
  85. * @return string
  86. */
  87. public function getCharset()
  88. {
  89. return $this->_charset;
  90. }
  91. /**
  92. * Set the language used in this Header.
  93. *
  94. * For example, for US English, 'en-us'.
  95. * This can be unspecified.
  96. *
  97. * @param string $lang
  98. */
  99. public function setLanguage($lang)
  100. {
  101. $this->clearCachedValueIf($this->_lang != $lang);
  102. $this->_lang = $lang;
  103. }
  104. /**
  105. * Get the language used in this Header.
  106. *
  107. * @return string
  108. */
  109. public function getLanguage()
  110. {
  111. return $this->_lang;
  112. }
  113. /**
  114. * Set the encoder used for encoding the header.
  115. *
  116. * @param Swift_Mime_HeaderEncoder $encoder
  117. */
  118. public function setEncoder(Swift_Mime_HeaderEncoder $encoder)
  119. {
  120. $this->_encoder = $encoder;
  121. $this->setCachedValue(null);
  122. }
  123. /**
  124. * Get the encoder used for encoding this Header.
  125. *
  126. * @return Swift_Mime_HeaderEncoder
  127. */
  128. public function getEncoder()
  129. {
  130. return $this->_encoder;
  131. }
  132. /**
  133. * Set the grammar used for the header.
  134. *
  135. * @param Swift_Mime_Grammar $grammar
  136. */
  137. public function setGrammar(Swift_Mime_Grammar $grammar)
  138. {
  139. $this->_grammar = $grammar;
  140. $this->setCachedValue(null);
  141. }
  142. /**
  143. * Get the grammar used for this Header.
  144. *
  145. * @return Swift_Mime_Grammar
  146. */
  147. public function getGrammar()
  148. {
  149. return $this->_grammar;
  150. }
  151. /**
  152. * Get the name of this header (e.g. charset).
  153. *
  154. * @return string
  155. */
  156. public function getFieldName()
  157. {
  158. return $this->_name;
  159. }
  160. /**
  161. * Set the maximum length of lines in the header (excluding EOL).
  162. *
  163. * @param integer $lineLength
  164. */
  165. public function setMaxLineLength($lineLength)
  166. {
  167. $this->clearCachedValueIf($this->_lineLength != $lineLength);
  168. $this->_lineLength = $lineLength;
  169. }
  170. /**
  171. * Get the maximum permitted length of lines in this Header.
  172. *
  173. * @return int
  174. */
  175. public function getMaxLineLength()
  176. {
  177. return $this->_lineLength;
  178. }
  179. /**
  180. * Get this Header rendered as a RFC 2822 compliant string.
  181. *
  182. * @return string
  183. *
  184. * @throws Swift_RfcComplianceException
  185. */
  186. public function toString()
  187. {
  188. return $this->_tokensToString($this->toTokens());
  189. }
  190. /**
  191. * Returns a string representation of this object.
  192. *
  193. * @return string
  194. *
  195. * @see toString()
  196. */
  197. public function __toString()
  198. {
  199. return $this->toString();
  200. }
  201. // -- Points of extension
  202. /**
  203. * Set the name of this Header field.
  204. *
  205. * @param string $name
  206. */
  207. protected function setFieldName($name)
  208. {
  209. $this->_name = $name;
  210. }
  211. /**
  212. * Produces a compliant, formatted RFC 2822 'phrase' based on the string given.
  213. *
  214. * @param Swift_Mime_Header $header
  215. * @param string $string as displayed
  216. * @param string $charset of the text
  217. * @param Swift_Mime_HeaderEncoder $encoder
  218. * @param boolean $shorten the first line to make remove for header name
  219. *
  220. * @return string
  221. */
  222. protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false)
  223. {
  224. //Treat token as exactly what was given
  225. $phraseStr = $string;
  226. //If it's not valid
  227. if (!preg_match('/^' . $this->getGrammar()->getDefinition('phrase') . '$/D', $phraseStr)) {
  228. // .. but it is just ascii text, try escaping some characters
  229. // and make it a quoted-string
  230. if (preg_match('/^' . $this->getGrammar()->getDefinition('text') . '*$/D', $phraseStr)) {
  231. $phraseStr = $this->getGrammar()->escapeSpecials(
  232. $phraseStr, array('"'), $this->getGrammar()->getSpecials()
  233. );
  234. $phraseStr = '"' . $phraseStr . '"';
  235. } else { // ... otherwise it needs encoding
  236. //Determine space remaining on line if first line
  237. if ($shorten) {
  238. $usedLength = strlen($header->getFieldName() . ': ');
  239. } else {
  240. $usedLength = 0;
  241. }
  242. $phraseStr = $this->encodeWords($header, $string, $usedLength);
  243. }
  244. }
  245. return $phraseStr;
  246. }
  247. /**
  248. * Encode needed word tokens within a string of input.
  249. *
  250. * @param Swift_Mime_Header $header
  251. * @param string $input
  252. * @param string $usedLength optional
  253. *
  254. * @return string
  255. */
  256. protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1)
  257. {
  258. $value = '';
  259. $tokens = $this->getEncodableWordTokens($input);
  260. foreach ($tokens as $token) {
  261. //See RFC 2822, Sect 2.2 (really 2.2 ??)
  262. if ($this->tokenNeedsEncoding($token)) {
  263. //Don't encode starting WSP
  264. $firstChar = substr($token, 0, 1);
  265. switch ($firstChar) {
  266. case ' ':
  267. case "\t":
  268. $value .= $firstChar;
  269. $token = substr($token, 1);
  270. }
  271. if (-1 == $usedLength) {
  272. $usedLength = strlen($header->getFieldName() . ': ') + strlen($value);
  273. }
  274. $value .= $this->getTokenAsEncodedWord($token, $usedLength);
  275. $header->setMaxLineLength(76); //Forcefully override
  276. } else {
  277. $value .= $token;
  278. }
  279. }
  280. return $value;
  281. }
  282. /**
  283. * Test if a token needs to be encoded or not.
  284. *
  285. * @param string $token
  286. *
  287. * @return boolean
  288. */
  289. protected function tokenNeedsEncoding($token)
  290. {
  291. return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token);
  292. }
  293. /**
  294. * Splits a string into tokens in blocks of words which can be encoded quickly.
  295. *
  296. * @param string $string
  297. *
  298. * @return string[]
  299. */
  300. protected function getEncodableWordTokens($string)
  301. {
  302. $tokens = array();
  303. $encodedToken = '';
  304. //Split at all whitespace boundaries
  305. foreach (preg_split('~(?=[\t ])~', $string) as $token) {
  306. if ($this->tokenNeedsEncoding($token)) {
  307. $encodedToken .= $token;
  308. } else {
  309. if (strlen($encodedToken) > 0) {
  310. $tokens[] = $encodedToken;
  311. $encodedToken = '';
  312. }
  313. $tokens[] = $token;
  314. }
  315. }
  316. if (strlen($encodedToken)) {
  317. $tokens[] = $encodedToken;
  318. }
  319. return $tokens;
  320. }
  321. /**
  322. * Get a token as an encoded word for safe insertion into headers.
  323. *
  324. * @param string $token token to encode
  325. * @param integer $firstLineOffset optional
  326. *
  327. * @return string
  328. */
  329. protected function getTokenAsEncodedWord($token, $firstLineOffset = 0)
  330. {
  331. //Adjust $firstLineOffset to account for space needed for syntax
  332. $charsetDecl = $this->_charset;
  333. if (isset($this->_lang)) {
  334. $charsetDecl .= '*' . $this->_lang;
  335. }
  336. $encodingWrapperLength = strlen(
  337. '=?' . $charsetDecl . '?' . $this->_encoder->getName() . '??='
  338. );
  339. if ($firstLineOffset >= 75) { //Does this logic need to be here?
  340. $firstLineOffset = 0;
  341. }
  342. $encodedTextLines = explode("\r\n",
  343. $this->_encoder->encodeString(
  344. $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset
  345. )
  346. );
  347. if (strtolower($this->_charset) !== 'iso-2022-jp') { // special encoding for iso-2022-jp using mb_encode_mimeheader
  348. foreach ($encodedTextLines as $lineNum => $line) {
  349. $encodedTextLines[$lineNum] = '=?' . $charsetDecl .
  350. '?' . $this->_encoder->getName() .
  351. '?' . $line . '?=';
  352. }
  353. }
  354. return implode("\r\n ", $encodedTextLines);
  355. }
  356. /**
  357. * Generates tokens from the given string which include CRLF as individual tokens.
  358. *
  359. * @param string $token
  360. *
  361. * @return string[]
  362. */
  363. protected function generateTokenLines($token)
  364. {
  365. return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE);
  366. }
  367. /**
  368. * Set a value into the cache.
  369. *
  370. * @param string $value
  371. */
  372. protected function setCachedValue($value)
  373. {
  374. $this->_cachedValue = $value;
  375. }
  376. /**
  377. * Get the value in the cache.
  378. *
  379. * @return string
  380. */
  381. protected function getCachedValue()
  382. {
  383. return $this->_cachedValue;
  384. }
  385. /**
  386. * Clear the cached value if $condition is met.
  387. *
  388. * @param boolean $condition
  389. */
  390. protected function clearCachedValueIf($condition)
  391. {
  392. if ($condition) {
  393. $this->setCachedValue(null);
  394. }
  395. }
  396. // -- Private methods
  397. /**
  398. * Generate a list of all tokens in the final header.
  399. *
  400. * @param string $string The string to tokenize
  401. *
  402. * @return array An array of tokens as strings
  403. */
  404. protected function toTokens($string = null)
  405. {
  406. if (is_null($string)) {
  407. $string = $this->getFieldBody();
  408. }
  409. $tokens = array();
  410. //Generate atoms; split at all invisible boundaries followed by WSP
  411. foreach (preg_split('~(?=[ \t])~', $string) as $token) {
  412. $tokens = array_merge($tokens, $this->generateTokenLines($token));
  413. }
  414. return $tokens;
  415. }
  416. /**
  417. * Takes an array of tokens which appear in the header and turns them into
  418. * an RFC 2822 compliant string, adding FWSP where needed.
  419. *
  420. * @param string[] $tokens
  421. *
  422. * @return string
  423. */
  424. private function _tokensToString(array $tokens)
  425. {
  426. $lineCount = 0;
  427. $headerLines = array();
  428. $headerLines[] = $this->_name . ': ';
  429. $currentLine =& $headerLines[$lineCount++];
  430. //Build all tokens back into compliant header
  431. foreach ($tokens as $i => $token) {
  432. //Line longer than specified maximum or token was just a new line
  433. if (("\r\n" == $token) ||
  434. ($i > 0 && strlen($currentLine . $token) > $this->_lineLength)
  435. && 0 < strlen($currentLine))
  436. {
  437. $headerLines[] = '';
  438. $currentLine =& $headerLines[$lineCount++];
  439. }
  440. //Append token to the line
  441. if ("\r\n" != $token) {
  442. $currentLine .= $token;
  443. }
  444. }
  445. //Implode with FWS (RFC 2822, 2.2.3)
  446. return implode("\r\n", $headerLines) . "\r\n";
  447. }
  448. }