Source for file Header.php
Documentation is available at Header.php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
// +-----------------------------------------------------------------------+
// | http://www.heino.gehlsen.dk/software/license |
// +-----------------------------------------------------------------------+
// | This work (including software, documents, or other related items) is |
// | being provided by the copyright holders under the following license. |
// | By obtaining, using and/or copying this work, you (the licensee) |
// | agree that you have read, understood, and will comply with the |
// | following terms and conditions: |
// | Permission to use, copy, modify, and distribute this software and |
// | its documentation, with or without modification, for any purpose and |
// | without fee or royalty is hereby granted, provided that you include |
// | the following on ALL copies of the software and documentation or |
// | portions thereof, including modifications, that you make: |
// | 1. The full text of this NOTICE in a location viewable to users of |
// | the redistributed or derivative work. |
// | 2. Any pre-existing intellectual property disclaimers, notices, or |
// | terms and conditions. If none exist, a short notice of the |
// | following form (hypertext is preferred, text is permitted) should |
// | be used within the body of any redistributed or derivative code: |
// | http://www.heino.gehlsen.dk/software/license" |
// | 3. Notice of any changes or modifications to the files, including |
// | the date changes were made. (We recommend you provide URIs to |
// | the location from which the code is derived.) |
// | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT |
// | HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, |
// | INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR |
// | FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE |
// | OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, |
// | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. |
// | COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, |
// | SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE |
// | SOFTWARE OR DOCUMENTATION. |
// | The name and trademarks of copyright holders may NOT be used in |
// | advertising or publicity pertaining to the software without specific, |
// | written prior permission. Title to copyright in this software and any |
// | associated documentation will at all times remain with copyright |
// +-----------------------------------------------------------------------+
// | except for the references to the copyright holder, which has either |
// | been changes or removed. |
// +-----------------------------------------------------------------------+
// $Id: Header.php,v 1.11.6.1 2005/03/28 16:26:58 heino Exp $
define('NET_NNTP_HEADER_SET_UNFOLD', 1 );
define('NET_NNTP_HEADER_SET_DECODE', 2 );
define('NET_NNTP_HEADER_SET_CLEAN', 4 );
define('NET_NNTP_HEADER_SET_KEEPCASE', 8 );
define('NET_NNTP_HEADER_SET_DEFAULT', NET_NNTP_HEADER_SET_CLEAN | NET_NNTP_HEADER_SET_UNFOLD | NET_NNTP_HEADER_SET_DECODE );
define('NET_NNTP_HEADER_GET_FOLD', 1 );
define('NET_NNTP_HEADER_GET_ENCODE', 2 );
define('NET_NNTP_HEADER_GET_DEFAULT', NET_NNTP_HEADER_GET_ENCODE | NET_NNTP_HEADER_GET_FOLD );
* The Net_NNTP_Header class
* @author Heino H. Gehlsen <heino@gehlsen.dk>
* @version $Id: Header.php,v 1.11.6.1 2005/03/28 16:26:58 heino Exp $
* @since Class available since Release 0.10.0
* Container for the header fields
* Reset the field container
* Create a new instance of Net_NNTP_Header
* @param optional mixed $input Can be any of the following:
* (string) RFC2822 style header lines (CRLF included)
* (array) RFC2822 style header lines (CRLF not included)
* (object) Net_NNTP_Header object
* (object) Net_NNTP_Message object
* @return object Net_NNTP_Header object
function & create($input = null )
case is_a($input, 'net_nntp_header'):
$return->setFields ($input);
case is_a($input, 'net_nntp_message'):
$return->setFields ($input);
return PEAR ::throwError ('Unsupported object/class: '. get_class($input), null );
$R = $Object->setFields ($input);
return PEAR ::throwError ('Unsupported object/class: '. get_class($input), null );
* @param optional int $index
function add($tag, $value, $index = null )
// Add header to $return array
// The header name has already been used at least two times.
$this->fields[$tag][] = $value;
} elseif (isset ($this->fields[$tag])) {
// The header name has already been used one time -> change to nedted values.
// The header name has not used until now.
* Replace a field's value
* @param optional int $index
function replace($tag, $value, $index = null )
if (isset ($this->fields[$tag])) {
$this->fields[$tag][$index] = $value;
//TODO: Currently ignores $index, and just replaces the value
* @param optional int $index
function delete($tag, $index = null )
if (isset ($this->fields[$tag])) {
unset ($this->fields[$tag][$index]);
* Gets the value of a header field
* @param optional int $index (defaults to 0)
function get($tag, $index = 0 )
if (!isset ($this->fields[$tag])) {
return $this->fields[$tag][$index];
* Gets the values of a all occurences of a field
* @param optional int $index
if (!isset ($this->fields[$tag])) {
// TODO: What to do, when not array but index is set...
return array ($this->fields[$tag]);
* Returns the number of times the given field tag appears in the header.
if (!isset ($this->fields[$tag])) {
* Returns an array of all the tags that exist in the header.
* Each tag will only appear in the list once.
* Remove any header field that only contains whitespace.
unset ($this->fields[$tag][$i]);
* Import RFC2822 style header lines given in $input into the object
* @param mixed $input Can be any of the following:
* (string) RFC2822 style header lines (CRLF included)
* (array) RFC2822 style header lines (CRLF not included)
* (object) Net_NNTP_Header object
* (object) Net_NNTP_Message object
function setFields(&$input, $flags = NET_NNTP_HEADER_SET_DEFAULT )
case is_a($input, 'net_nntp_header'):
$this->fields = $input->getFields ();
case is_a($input, 'net_nntp_message'):
$h = $input->getHeader ();
return PEAR ::throwError ('Unsupported object/class: '. get_class($input), null );
$this->fields = $this->_parseString ($input, $flags);
$this->fields = $this->_parseArray ($input, $flags);
return PEAR ::throwError ('Unsupported type: '. gettype($input), null );
* Get the array of header fields.
* Export a string of RFC2822 style header style lines from the object.
* @return string RFC2822 style header lines (CRLF included)
return $this->_regenerateString ($this->fields, $flags);
* Export an array of RFC2822 style header style lines from the object.
* @return array RFC2822 style header lines (CRLF not included)
return $this->_regenerateArray ($this->fields, $flags);
* Parse a string of RFC2822 style header lines into a 'header array' with the header names as keys.
* @param string $string RFC2822 style header lines (CRLF included)
* @return array 'header array' with the header names as keys, values may be nested.
function _parseString ($string, $flags)
// Clean the header lines
// Unfold the header lines
// Remove body if present
return $this->_parse ($array, $flags);
* Parse an array of RFC2822 style header lines into a 'header array' with the header names as keys.
* @param array $array RFC2822 style header lines (CRLF not included)
* @return array 'header array' with the header names as keys, values may be nested.
function _parseArray ($array, $flags)
// Clean the header lines
// Unfold the header lines
// Remove body if present
return $this->_parse ($array, $flags);
* Parse a cleaned and unfolded array of RFC2822 style header lines into a 'header array' with the header names as keys.
* When header names a'pear more the once, the resulting array will have the values nested in the order of a'pear'ence.
* @param array $array RFC2822 style header lines (CRLF not included)
* @return array 'header array' with the header names as keys, values may be nested.
function _parse ($array, $flags)
// Loop through all headers
foreach ($array as $field) {
// Separate header name and value
if (!preg_match('/([\S]+)\:\s*(.*)\s*/', $field, $matches)) {
// Change header name to lower case
// Decode header value acording to RFC 2047
// Add header to $return array
if (isset ($return[$name]) AND is_array($return[$name])) {
// The header name has already been used at least two times.
$return[$name][] = $value;
} elseif (isset ($return[$name])) {
// The header name has already been used one time -> change to nedted values.
$return[$name] = array ($return[$name], $value);
// The header name has not used until now.
// {{{ _regenerateString()
* Generate a string of RFC2822 style header lines from the 'header array' given in $array.
* @param array $array RFC2822 style header lines
* @return string RFC822 style header lines (CRLF included).
function _regenerateString ($array, $flags)
// ( Forward to _regenerateArray() and then convert to string )
return implode("\r\n", $this->_regenerateArray ($array, $flags));
// {{{ _regenerateArray()
* Generate an array of RFC2822 style header lines from the array given in $array.
* @param array $array 'header field array'
* @return array RFC822 style header lines (CRLF not included).
function _regenerateArray ($array, $flags)
foreach ($array as $name => $value) {
// Encode header values acording to RFC 2047
foreach ($value as $sub_value) {
$return[] = $name. ': '. $sub_value;
$return[] = $name. ': '. $value;
* Do the (RFC822 3.1.1) header unfolding to a string of RFC2822 header lines.
* @param string $string RFC2822 header lines to unfolded (CRLF included)
* @return string Unfolded RFC2822 header lines (CRLF included)
// Unfold multiline headers
* Do the (RFC822 3.1.1) header unfolding to an array of RFC2822 header lines.
* @param array $array RFC2822 header lines to unfolded (CRLF not included)
* @return array Unfolded RFC2822 header lines (CRLF not included)
// Unfold multiline headers
for ($i = count($array)-1; $i>0; $i-- ) {
// Check for leading whitespace
if (substr($array[$i-1 ], -2 ) == "\r\n") {
$array[$i-1 ] = substr($array[$i-1 ], 0 , -2 );
// Append folded line to prev line
$array[$i-1 ] = $array[$i-1 ]. ' '. ltrim($array[$i], " \t");
* Folds an array of RFC2822 style header lines.
* @param optional int $maxlen
$tmp = $this->_foldExplode ($array[$key], $maxlen);
$return[] = $prepend. $tmp[$key2];
* Folds a string by inserting CRLF's and TAB's where allowed
* @param optional int $maxlen
$array = $this->_foldExplode ($string, $maxlen);
$return = implode("\r\n\t", $array);
* Unfold $string, and return a 'folded' array
* The current implementation is still experimental, and is NOT expected to comply with RFC2822 !!!
* @param optional int $maxlen
function _foldExplode ($string, $maxlen = 78 )
if (strlen($string) <= $maxlen) {
$min = (int) ($maxlen * (2/5 )) - 4;
$max = $maxlen - 5; // 4 for leading spcs + 1 for [\,\;]
// try splitting at ',' or ';' >2/5 along the line
// next split a whitespace
// else we are looking at a single word and probably don't want to split
$exp[] = " [^\"]\{$min,$max}?[\,\;]\s";
$exp[] = " [^\"]\{1,$max}\s";
$exp[] = "[^\s\"]*(?:\"[^\"]*\"[^\s\"]*)+\s";
$exp = "/^\s*(". implode('|', $exp). ")(.*)\$/x";
* Given a header/string, this function will decode it according to RFC2047.
* Probably not *exactly* conformant, but it does pass all the given
* @param string $input Input header value to decode
* @return string Decoded header value
// Remove white space between encoded-words
$input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
// For each encoded-word...
while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
foreach($matches[1 ] as $value)
* Encodes the string given in $string as per RFC2047
* @param string $string The string to encode
* @return string Encoded string
// TODO: could be better! (Look into CPAN's Encode::MIME::Header)
foreach ($matches[1 ] as $value) {
$replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
$string = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $string);
* Removes CRLF and misplaced empty lines before and after actual headerlines.
// Correct missing CR's before LF's
// Remove empty lines from start and end.
// TODO: This should be done better...
$string = trim($string, "\r\n");
* Removes CRLF and misplaced empty lines before and after actual headerlines.
// Remove empty lines from the start
while (reset($input) == "\r\n") {
// Remove empty lines from the end
while (end($input) == "\r\n") {
// Run backwards through all lines
for ($i = count($input)-1; $i > 0; $i-- ) {
// Remove \r\n from the end
Documentation generated on Mon, 11 Mar 2019 14:30:58 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|