[ Index ] |
|
Code source de Horde 3.1.3 |
1 <?php 2 /** 3 * The Text_Flowed:: class provides common methods for manipulating text 4 * using the encoding described in RFC 3676 ('flowed' text). 5 * 6 * $Horde: framework/Text_Flowed/Flowed.php,v 1.14.10.17 2006/03/11 09:50:22 jan Exp $ 7 * 8 * This class is based on the Text::Flowed perl module (Version 0.14) found 9 * in the CPAN perl repository. This module is released under the Perl 10 * license, which is compatible with the LGPL. 11 * 12 * Copyright 2002-2003 Philip Mak 13 * Copyright 2004-2006 Michael Slusarz <slusarz@bigworm.colorado.edu> 14 * 15 * See the enclosed file COPYING for license information (LGPL). If you 16 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. 17 * 18 * @author Michael Slusarz <slusarz@bigworm.colorado.edu> 19 * @since Horde 3.0 20 * @package Horde_Text 21 */ 22 class Text_Flowed { 23 24 /** 25 * The maximum length that a line is allowed to be (unless faced with 26 * with a word that is unreasonably long). This class will re-wrap a 27 * line if it exceeds this length. 28 * 29 * @var integer 30 */ 31 var $_maxlength = 78; 32 33 /** 34 * When this class wraps a line, the newly created lines will be split 35 * at this length. 36 * 37 * @var integer 38 */ 39 var $_optlength = 72; 40 41 /** 42 * The text to be formatted. 43 * 44 * @var string 45 */ 46 var $_text; 47 48 /** 49 * The cached output of the formatting. 50 * 51 * @var array 52 */ 53 var $_output = null; 54 55 /** 56 * The character set of the text. 57 * 58 * @var string 59 */ 60 var $_charset; 61 62 /** 63 * Convert text using DelSp? 64 * 65 * @var boolean 66 */ 67 var $_delsp = false; 68 69 /** 70 * Constructor. 71 * 72 * @param string $text The text to process. 73 * @param string $charset The character set of $text. 74 */ 75 function Text_Flowed($text, $charset = null) 76 { 77 $this->_text = $text; 78 $this->_charset = $charset; 79 } 80 81 /** 82 * Set the maximum length of a line of text. 83 * 84 * @param integer $max A new value for $_maxlength. 85 */ 86 function setMaxLength($max) 87 { 88 $this->_maxlength = $max; 89 } 90 91 /** 92 * Set the optimal length of a line of text. 93 * 94 * @param integer $max A new value for $_optlength. 95 */ 96 function setOptLength($opt) 97 { 98 $this->_optlength = $opt; 99 } 100 101 /** 102 * Set whether to format test using DelSp. 103 * 104 * @since Horde 3.1 105 * 106 * @param boolean $delsp Use DelSp? 107 */ 108 function setDelSp($delsp) 109 { 110 $this->_delsp = (bool) $delsp; 111 } 112 113 /** 114 * Reformats the input string, where the string is 'format=flowed' plain 115 * text as described in RFC 2646. 116 * 117 * @param boolean $quote Add level of quoting to each line? 118 * 119 * @return string The text converted to RFC 2646 'fixed' format. 120 */ 121 function toFixed($quote = false) 122 { 123 $txt = ''; 124 125 $this->_reformat(false, $quote); 126 foreach ($this->_output as $val) { 127 $txt .= $val['text'] . "\n"; 128 } 129 return rtrim($txt); 130 } 131 132 /** 133 * Reformats the input string, and returns the output in an array format 134 * with quote level information. 135 * 136 * @param boolean $quote Add level of quoting to each line? 137 * 138 * @return array An array of arrays with the following elements: 139 * <pre> 140 * 'level' - The quote level of the current line. 141 * 'text' - The text for the current line. 142 * </pre> 143 */ 144 function toFixedArray($quote = false) 145 { 146 $this->_reformat(false, $quote); 147 return $this->_output; 148 } 149 150 /** 151 * Reformats the input string, where the string is 'format=fixed' plain 152 * text as described in RFC 2646. 153 * 154 * @param boolean $quote Add level of quoting to each line? 155 * 156 * @return string The text converted to RFC 2646 'flowed' format. 157 */ 158 function toFlowed($quote = false) 159 { 160 $txt = ''; 161 162 $this->_reformat(true, $quote); 163 foreach ($this->_output as $val) { 164 $txt .= $val['text'] . "\n"; 165 } 166 return $txt; 167 } 168 169 /** 170 * Reformats the input string, where the string is 'format=flowed' plain 171 * text as described in RFC 2646. 172 * 173 * @access private 174 * 175 * @param boolean $toflowed Convert to flowed? 176 * @param boolean $quote Add level of quoting to each line? 177 * 178 * @return array A list of arrays. 179 */ 180 function _reformat($toflowed, $quote) 181 { 182 if (!is_null($this->_output)) { 183 return; 184 } 185 186 $this->_output = array(); 187 $text = explode("\n", $this->_text); 188 189 /* Set variables used in regexps. */ 190 $delsp = ($toflowed && $this->_delsp) ? 1 : 0; 191 $opt = $this->_optlength - 1 - $delsp; 192 193 /* Process message line by line. */ 194 do { 195 $line = array_shift($text); 196 197 /* Per RFC 2646 [4.3], the 'Usenet Signature Convention' line 198 * (DASH DASH SP) is not considered flowed. Watch for this when 199 * dealing with potentially flowed lines. */ 200 201 /* The next three steps come from RFC 2646 [4.2]. */ 202 /* STEP 1: Determine quote level for line. */ 203 if (($num_quotes = $this->_numquotes($line))) { 204 $line = substr($line, $num_quotes); 205 } 206 207 /* Only combine lines if we are converting to flowed or if the 208 * current line is quoted. */ 209 if (!$toflowed || $num_quotes) { 210 /* STEP 2: Remove space stuffing from line. */ 211 $line = $this->_unstuff($line); 212 213 /* STEP 3: Should we interpret this line as flowed? 214 * While line is flowed (not empty and there is a space 215 * at the end of the line), and there is a next line, and the 216 * next line has the same quote depth, add to the current 217 * line. A line is not flowed if it is a signature line. */ 218 while (!empty($line) && 219 ($line != '-- ') && 220 ($line{strlen($line)-1} == ' ') && 221 !empty($text) && 222 ($this->_numquotes($text[0]) == $num_quotes)) { 223 /* If DelSp is yes and this is flowed input, we need to 224 * remove the trailing space. */ 225 if (!$toflowed && $this->_delsp) { 226 $line = substr($line, 0, -1); 227 } 228 $line .= $this->_unstuff(substr(array_shift($text), $num_quotes)); 229 } 230 } 231 232 /* Ensure line is fixed, since we already joined all flowed 233 * lines. Remove all trailing ' ' from the line. */ 234 if ($line != '-- ') { 235 $line = rtrim($line); 236 } 237 238 /* Increment quote depth if we're quoting. */ 239 if ($quote) { 240 $num_quotes++; 241 } 242 243 /* The quote prefix for the line. */ 244 $quotestr = str_repeat('>', $num_quotes); 245 246 if (empty($line)) { 247 /* Line is empty. */ 248 $this->_output[] = array('text' => $quotestr, 'level' => $num_quotes); 249 } elseif (empty($this->_maxlength) || ((String::length($line, $this->_charset) + $num_quotes) <= $this->_maxlength)) { 250 /* Line does not require rewrapping. */ 251 $this->_output[] = array('text' => $quotestr . $this->_stuff($line, $num_quotes, $toflowed), 'level' => $num_quotes); 252 } else { 253 $min = $num_quotes + 1; 254 255 /* Rewrap this paragraph. */ 256 while ($line) { 257 /* Stuff and re-quote the line. */ 258 $line = $quotestr . $this->_stuff($line, $num_quotes, $toflowed); 259 $line_length = String::length($line, $this->_charset); 260 if ($line_length <= $this->_optlength) { 261 /* Remaining section of line is short enough. */ 262 $this->_output[] = array('text' => $line, 'level' => $num_quotes); 263 break; 264 } elseif ($m = String::regexMatch($line, array('^(.{' . $min . ',' . $opt . '}) (.*)', '^(.{' . $min . ',' . $this->_maxlength . '}) (.*)', '^(.{' . $min . ',})? (.*)'), $this->_charset)) { 265 /* We need to wrap text at a certain number of 266 * *characters*, not a certain number of *bytes*; 267 * thus the need for a multibyte capable regex. 268 * If a multibyte regex isn't available, we are stuck 269 * with preg_match() (the function will still work - 270 * we will just be left with shorter rows than expected 271 * if multibyte characters exist in the row). 272 * 273 * Algorithim: 274 * 1. Try to find a string as long as _optlength. 275 * 2. Try to find a string as long as _maxlength. 276 * 3. Take the first word. */ 277 if (empty($m[1])) { 278 $m[1] = $m[2]; 279 $m[2] = ''; 280 } 281 $this->_output[] = array('text' => $m[1] . ' ' . (($delsp) ? ' ' : ''), 'level' => $num_quotes); 282 $line = $m[2]; 283 } else { 284 /* One excessively long word left on line. Be 285 * absolutely sure it does not exceed 998 characters 286 * in length or else we must truncate. */ 287 if ($line_length > 998) { 288 $this->_output[] = array('text' => String::substr($line, 0, 998, $this->_charset), 'level' => $num_quotes); 289 $line = String::substr($line, 998, null, $this->_charset); 290 } else { 291 $this->_output[] = array('text' => $line, 'level' => $num_quotes); 292 break; 293 } 294 } 295 } 296 } 297 } while (!empty($text)); 298 } 299 300 /** 301 * Returns the number of leading '>' characters in the text input. 302 * '>' characters are defined by RFC 2646 to indicate a quoted line. 303 * 304 * @access private 305 * 306 * @param string $text The text to analyze. 307 * 308 * @return integer The number of leading quote characters. 309 */ 310 function _numquotes($text) 311 { 312 return strspn($text, '>'); 313 } 314 315 /** 316 * Space-stuffs if it starts with ' ' or '>' or 'From ', or if 317 * quote depth is non-zero (for aesthetic reasons so that there is a 318 * space after the '>'). 319 * 320 * @access private 321 * 322 * @param string $text The text to stuff. 323 * @param string $num_quotes The quote-level of this line. 324 * @param boolean $toflowed Are we converting to flowed text? 325 * 326 * @return string The stuffed text. 327 */ 328 function _stuff($text, $num_quotes, $toflowed) 329 { 330 if ($toflowed && 331 ($num_quotes || preg_match("/^(?: |>|From |From$)/", $text))) { 332 return ' ' . $text; 333 } 334 return $text; 335 } 336 337 /** 338 * Unstuffs a space stuffed line. 339 * 340 * @access private 341 * 342 * @param string $text The text to unstuff. 343 * 344 * @return string The unstuffed text. 345 */ 346 function _unstuff($text) 347 { 348 if (!empty($text) && ($text{0} == ' ')) { 349 $text = substr($text, 1); 350 } 351 return $text; 352 } 353 354 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |