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

Source for file Header.php

Documentation is available at Header.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3. // +-----------------------------------------------------------------------+
  4. // |                                                                       |
  5. // |                  http://www.heino.gehlsen.dk/software/license         |
  6. // |                                                                       |
  7. // +-----------------------------------------------------------------------+
  8. // |                                                                       |
  9. // | This work (including software, documents, or other related items) is  |
  10. // | being provided by the copyright holders under the following license.  |
  11. // | By obtaining, using and/or copying this work, you (the licensee)      |
  12. // | agree that you have read, understood, and will comply with the        |
  13. // | following terms and conditions:                                       |
  14. // |                                                                       |
  15. // | Permission to use, copy, modify, and distribute this software and     |
  16. // | its documentation, with or without modification, for any purpose and  |
  17. // | without fee or royalty is hereby granted, provided that you include   |
  18. // | the following on ALL copies of the software and documentation or      |
  19. // | portions thereof, including modifications, that you make:             |
  20. // |                                                                       |
  21. // | 1. The full text of this NOTICE in a location viewable to users of    |
  22. // |    the redistributed or derivative work.                              |
  23. // |                                                                       |
  24. // | 2. Any pre-existing intellectual property disclaimers, notices, or    |
  25. // |    terms and conditions. If none exist, a short notice of the         |
  26. // |    following form (hypertext is preferred, text is permitted) should  |
  27. // |    be used within the body of any redistributed or derivative code:   |
  28. // |     http://www.heino.gehlsen.dk/software/license"                     |
  29. // |                                                                       |
  30. // | 3. Notice of any changes or modifications to the files, including     |
  31. // |    the date changes were made. (We recommend you provide URIs to      |
  32. // |    the location from which the code is derived.)                      |
  33. // |                                                                       |
  34. // | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT    |
  35. // | HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED,    |
  36. // | INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR        |
  37. // | FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE    |
  38. // | OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS,           |
  39. // | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.                               |
  40. // |                                                                       |
  41. // | COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT,        |
  42. // | SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE        |
  43. // | SOFTWARE OR DOCUMENTATION.                                            |
  44. // |                                                                       |
  45. // | The name and trademarks of copyright holders may NOT be used in       |
  46. // | advertising or publicity pertaining to the software without specific, |
  47. // | written prior permission. Title to copyright in this software and any |
  48. // | associated documentation will at all times remain with copyright      |
  49. // | holders.                                                              |
  50. // |                                                                       |
  51. // +-----------------------------------------------------------------------+
  52. // |                                                                       |
  53. // | except for the references to the copyright holder, which has either   |
  54. // | been changes or removed.                                              |
  55. // |                                                                       |
  56. // +-----------------------------------------------------------------------+
  57. // $Id: Header.php,v 1.11.6.1 2005/03/28 16:26:58 heino Exp $
  58.  
  59. require_once 'PEAR.php';
  60.  
  61. // {{{ constants
  62.  
  63. define('NET_NNTP_HEADER_SET_UNFOLD'1);
  64. define('NET_NNTP_HEADER_SET_DECODE'2);
  65. define('NET_NNTP_HEADER_SET_CLEAN'4);
  66. define('NET_NNTP_HEADER_SET_KEEPCASE'8);
  67. define('NET_NNTP_HEADER_SET_DEFAULT'NET_NNTP_HEADER_SET_CLEAN | NET_NNTP_HEADER_SET_UNFOLD | NET_NNTP_HEADER_SET_DECODE);
  68.  
  69. define('NET_NNTP_HEADER_GET_FOLD'1);
  70. define('NET_NNTP_HEADER_GET_ENCODE'2);
  71. define('NET_NNTP_HEADER_GET_DEFAULT'NET_NNTP_HEADER_GET_ENCODE | NET_NNTP_HEADER_GET_FOLD);
  72.  
  73. // }}}
  74. // {{{ Net_NNTP_Header
  75.  
  76. /**
  77.  * The Net_NNTP_Header class
  78.  *
  79.  * @category   Net
  80.  * @package    Net_NNTP
  81.  * @author     Heino H. Gehlsen <heino@gehlsen.dk>
  82.  * @version    $Id: Header.php,v 1.11.6.1 2005/03/28 16:26:58 heino Exp $
  83.  * @access     public
  84.  * @see        Net_NNTP_Message
  85.  * @since      Class available since Release 0.10.0
  86.  */
  87. {
  88.     // {{{ properties
  89.  
  90.     /**
  91.      * Container for the header fields
  92.      *
  93.      * @var    array 
  94.      * @access public
  95.      */
  96.     var $fields;
  97.  
  98.     // }}}
  99.     // {{{ constructor
  100.  
  101.     /**
  102.      * Constructor
  103.      *
  104.      * @access public
  105.      * @since 0.1
  106.      */
  107.     function Net_NNTP_Header()
  108.     {
  109.     // Reset object
  110.     $this->reset();
  111.     }
  112.  
  113.     // }}}
  114.     // {{{ reset()
  115.     
  116.     /**
  117.      * Reset the field container
  118.      * 
  119.      * @access public
  120.      * @since 0.1
  121.      */
  122.     function reset()
  123.     {
  124.     $this->fields = array();
  125.     }
  126.  
  127.     // }}}
  128.     // {{{ create()
  129.     
  130.     /**
  131.      * Create a new instance of Net_NNTP_Header
  132.      *
  133.      * @param optional mixed $input Can be any of the following:
  134.      *                                 (string) RFC2822 style header lines (CRLF included)
  135.      *                               (array)  RFC2822 style header lines (CRLF not included)
  136.      *                               (object) Net_NNTP_Header object
  137.      *                               (object) Net_NNTP_Message object
  138.      * 
  139.      * @return object Net_NNTP_Header object
  140.      * @access public
  141.      * @since 0.1
  142.      */
  143.     function create($input = null)
  144.     {
  145.     switch (true{
  146.  
  147.         // Null
  148.         case is_null($input);
  149.         $Object = new Net_NNTP_Header();
  150.             return $Object;
  151.         break;
  152.  
  153.         // Object
  154.         case is_object($input);
  155.         switch (true{
  156.             
  157.             // Header
  158.             case is_a($input'net_nntp_header'):
  159.                 $return = new Net_NNTP_Header();
  160.                 $return->setFields($input);
  161.                 return $return;
  162.             break;
  163.             
  164.             // Message
  165.             case is_a($input'net_nntp_message'):
  166.                 $return = new Net_NNTP_Header();
  167.                 $return->setFields($input);
  168.                 return $return;
  169.             break;
  170.             
  171.             // Unknown object/class
  172.             default:
  173.             return PEAR::throwError('Unsupported object/class: '.get_class($input)null);
  174.         }
  175.         break;
  176.  
  177.         // String & Array
  178.         case is_string($input);
  179.         case is_array($input);
  180.             $Object = new Net_NNTP_Header();
  181.         $R $Object->setFields($input);
  182.         if (PEAR::isError($R)) {
  183.             return $R;
  184.         }
  185.         return $Object;
  186.         break;
  187.  
  188.         // Unknown type
  189.         default:
  190.         return PEAR::throwError('Unsupported object/class: '.get_class($input)null);
  191.     }
  192.     }
  193.  
  194.     // }}}
  195.     // {{{ add()
  196.     
  197.     /**
  198.      * Add a new field
  199.      * 
  200.      * @param string $tag 
  201.      * @param string $value 
  202.      * @param optional int $index
  203.      * 
  204.      * @access public
  205.      * @since 0.1
  206.      */
  207.     function add($tag$value$index = null)
  208.     {
  209.     // Add header to $return array
  210.         if (isset($this->fields[$tag]&& is_array($this->fields[$tag])) {
  211.         // The header name has already been used at least two times.
  212.             $this->fields[$tag][$value;
  213.         elseif (isset($this->fields[$tag])) {
  214.         // The header name has already been used one time -> change to nedted values.
  215.             $this->fields[$tag= array($this->fields[$tag]$value);
  216.         else {
  217.         // The header name has not used until now.
  218.         $this->fields[$tag$value;
  219.         }
  220.     }
  221.  
  222.     // }}}
  223.     // {{{ replace()
  224.     
  225.     /**
  226.      * Replace a field's value
  227.      * 
  228.      * @param string $tag 
  229.      * @param string $value 
  230.      * @param optional int $index
  231.      * 
  232.      * @access public
  233.      * @since 0.1
  234.      */
  235.     function replace($tag$value$index = null)
  236.     {
  237.     if (isset($this->fields[$tag])) {
  238.         if ($index === null{
  239.         $this->fields[$tag$value;
  240.         else {
  241.         if (is_array($this->fields[$tag])) {
  242.             $this->fields[$tag][$index$value;
  243.         else {
  244. //TODO: Currently ignores $index, and just replaces the value
  245.             $this->fields[$tag$value;
  246.         }
  247.         }
  248.     else {
  249.         $this->fields[$tag$value;
  250.     }
  251.     }
  252.  
  253.     // }}}
  254.     // {{{ delete()
  255.     
  256.     /**
  257.      * Delete a field
  258.      * 
  259.      * @param string $tag 
  260.      * @param optional int $index
  261.      * 
  262.      * @access public
  263.      * @since 0.1
  264.      */
  265.     function delete($tag$index = null)
  266.     {
  267.     if (isset($this->fields[$tag])) {
  268.         if ($index == null{
  269.         unset($this->fields[$tag]);
  270.         else {
  271.         if (is_array($this->fields[$tag])) {
  272.             unset($this->fields[$tag][$index]);
  273.         else {
  274.             unset($this->fields[$tag]);
  275.         }
  276.         }
  277.     else {
  278.         // Do nothing...
  279.     }
  280.     }
  281.  
  282.     // }}}
  283.     // {{{ get()
  284.     
  285.     /**
  286.      * Gets the value of a header field
  287.      * 
  288.      * @param string $tag 
  289.      * @param optional int $index (defaults to 0)
  290.      * 
  291.      * @return string 
  292.      * @access public
  293.      * @since 0.1
  294.      */
  295.     function get($tag$index = 0)
  296.     {
  297.     if (!isset($this->fields[$tag])) {
  298.         return null;
  299.     }
  300.  
  301.     if (is_array($this->fields[$tag])) {
  302.         return $this->fields[$tag][$index];
  303.     else {
  304.         if ($index == 0{
  305.         return $this->fields[$tag];
  306.         else {
  307.             return null;
  308.         }
  309.     }
  310.     }
  311.  
  312.     // }}}
  313.     // {{{ getAll()
  314.     
  315.     /**
  316.      * Gets the values of a all occurences of a field
  317.      * 
  318.      * @param string $tag 
  319.      * @param optional int $index
  320.      * 
  321.      * @return array 
  322.      * @access public
  323.      * @since 0.1
  324.      */
  325.     function getAll($tag)
  326.     {
  327.     if (!isset($this->fields[$tag])) {
  328.         array();
  329.     }
  330.  
  331.     if (is_array($this->fields[$tag])) {
  332.         return $this->fields[$tag];
  333.     else {
  334. // TODO: What to do, when not array but index is set...
  335.         return array($this->fields[$tag]);
  336.     }
  337.     }
  338.  
  339.     // }}}
  340.     // {{{ count()
  341.     
  342.     /**
  343.      * Returns the number of times the given field tag appears in the header.
  344.      * 
  345.      * @param string $tag 
  346.      * 
  347.      * @return int 
  348.      * @access public
  349.      * @since 0.1
  350.      */
  351.     function count($tag)
  352.     {
  353.     if (!isset($this->fields[$tag])) {
  354.         return 0;
  355.     }
  356.  
  357.     if (is_array($this->fields[$tag])) {
  358.         return count($this->fields[$tag]);
  359.     else {
  360.         return 1;
  361.     }
  362.     }
  363.  
  364.     // }}}
  365.     // {{{ tags()
  366.     
  367.     /**
  368.      * Returns an array of all the tags that exist in the header.
  369.      * Each tag will only appear in the list once.
  370.      * 
  371.      * @return array 
  372.      * @access public
  373.      * @since 0.1
  374.      */
  375.     function tags()
  376.     {
  377.     return array_keys($this->fields);
  378.     }
  379.  
  380.     // }}}
  381.     // {{{ clean()
  382.     
  383.     /**
  384.      * Remove any header field that only contains whitespace.
  385.      * 
  386.      * @access public
  387.      * @since 0.1
  388.      */
  389.     function clean()
  390.     {
  391.     foreach (array_keys($this->fieldsas $tag{
  392.         if (is_array($this->fields[$tag])) {
  393.         foreach (array_keys($this->fields[$tag]as $i{
  394.             if (trim($this->fields[$tag][$i]== ''{
  395.             unset($this->fields[$tag][$i]);
  396.             }
  397.         }
  398.         else {
  399.         if (trim($this->fields[$tag]== ''{
  400.             unset($this->fields[$tag]);
  401.         }
  402.         }
  403.     }
  404.     }
  405.  
  406.     // }}}
  407.     // {{{ setFields()
  408.     
  409.     /**
  410.      * Import RFC2822 style header lines given in $input into the object
  411.      * 
  412.      * @param mixed $input Can be any of the following:
  413.      *                      (string) RFC2822 style header lines (CRLF included)
  414.      *                      (array)  RFC2822 style header lines (CRLF not included)
  415.      *                      (object) Net_NNTP_Header object
  416.      *                      (object) Net_NNTP_Message object
  417.      * @param optional $flags 
  418.      * 
  419.      * @access public
  420.      * @since 0.1
  421.      */
  422.     function setFields(&$input$flags = NET_NNTP_HEADER_SET_DEFAULT)
  423.     {
  424.     switch (true{
  425.  
  426.         // Object
  427.         case is_object($input):
  428.         switch (true{
  429.             case is_a($input'net_nntp_header'):
  430.             $this->reset();
  431.             $this->fields = $input->getFields();
  432.             break;
  433.             
  434.             case is_a($input'net_nntp_message'):
  435.             $h $input->getHeader();
  436.             $this->setFields($h);
  437.             break;
  438.             
  439.             // Unknown type
  440.             default:
  441.             return PEAR::throwError('Unsupported object/class: '.get_class($input)null);
  442.         }
  443.         break;
  444.  
  445.         // String
  446.         case is_string($input):
  447.         $this->fields = $this->_parseString($input$flags);
  448.         break;
  449.  
  450.         // Array
  451.         case is_array($input):
  452.         $this->fields = $this->_parseArray($input$flags);
  453.         break;
  454.  
  455.         // Unknown type
  456.         default:
  457.         return PEAR::throwError('Unsupported type: '.gettype($input)null);
  458.     }
  459.     }
  460.  
  461.     // }}}
  462.     // {{{ getFields()
  463.  
  464.     /**
  465.      * Get the array of header fields.
  466.      * 
  467.      * @param optional $flags 
  468.      *
  469.      * @return array 
  470.      * @access public
  471.      * @since 0.1
  472.      */
  473.     function getFields()
  474.     {
  475.     return $this->fields;
  476.     }
  477.  
  478.     // }}}
  479.     // {{{ getFieldsString()
  480.  
  481.     /**
  482.      * Export a string of RFC2822 style header style lines from the object.
  483.      * 
  484.      * @param optional $flags 
  485.      *
  486.      * @return string RFC2822 style header lines (CRLF included)
  487.      * @access public
  488.      * @since 0.1
  489.      */
  490.     function getFieldsString($flags = NET_NNTP_HEADER_GET_DEFAULT)
  491.     {
  492.     return $this->_regenerateString($this->fields$flags);
  493.     }
  494.  
  495.     // }}}
  496.     // {{{ getFieldsArray()
  497.  
  498.     /**
  499.      * Export an array of RFC2822 style header style lines from the object.
  500.      *
  501.      * @param optional $flags 
  502.      *
  503.      * @return array RFC2822 style header lines (CRLF not included)
  504.      * @access public
  505.      * @since 0.1
  506.      */
  507.     function getFieldsArray($flags = NET_NNTP_HEADER_GET_DEFAULT)
  508.     {
  509.     return $this->_regenerateArray($this->fields$flags);
  510.     }
  511.  
  512.     // }}}
  513.     // {{{ _parseString()
  514.     
  515.     /**
  516.      * Parse a string of RFC2822 style header lines into a 'header array' with the header names as keys.
  517.      * 
  518.      * @param string $string RFC2822 style header lines (CRLF included)
  519.      * @param optional $flags 
  520.      * 
  521.      * @return array 'header array' with the header names as keys, values may be nested.
  522.      * @access private
  523.      * @since 0.1
  524.      */
  525.     function _parseString($string$flags)
  526.     {
  527.         // Clean the header lines
  528.     if (($flags NET_NNTP_HEADER_SET_CLEAN== NET_NNTP_HEADER_SET_CLEAN{
  529.         $string $this->cleanString($string);
  530.     }
  531.  
  532.         // Unfold the header lines
  533.     if (($flags NET_NNTP_HEADER_SET_UNFOLD== NET_NNTP_HEADER_SET_UNFOLD{
  534.         $string $this->unfoldString($string);
  535.     }
  536.  
  537.     // Convert to array
  538.     $array explode("\r\n"$string);
  539.  
  540.     // Remove body if present
  541.     $i array_search(''$array);
  542.     if ($i != null{
  543.         array_splice($array$i(count($array))-$i);
  544.     }
  545.  
  546.     // Forward to _parse()
  547.     return $this->_parse($array$flags);
  548.     }
  549.  
  550.     // }}}
  551.     // {{{ _parseArray()
  552.  
  553.     /**
  554.      * Parse an array of RFC2822 style header lines into a 'header array' with the header names as keys.
  555.      * 
  556.      * @param array $array RFC2822 style header lines (CRLF not included)
  557.      * @param optional $flags 
  558.      *
  559.      * @return array 'header array' with the header names as keys, values may be nested.
  560.      * @access private
  561.      * @since 0.1
  562.      */
  563.     function _parseArray($array$flags)
  564.     {
  565.         // Clean the header lines
  566.     if (($flags NET_NNTP_HEADER_SET_CLEAN== NET_NNTP_HEADER_SET_CLEAN{
  567.         $array $this->cleanArray($array);
  568.     }
  569.  
  570.         // Unfold the header lines
  571.     if (($flags NET_NNTP_HEADER_SET_UNFOLD== NET_NNTP_HEADER_SET_UNFOLD{
  572.         $array $this->unfoldArray($array);
  573.     }
  574.  
  575.     // Remove body if present
  576.     $i array_search(''$array);
  577.     if ($i != null{
  578.         array_splice($array$icount($array)-$i);
  579.     }
  580.  
  581.     // Forward to _parse()
  582.     return $this->_parse($array$flags);
  583.     }
  584.  
  585.     // }}}
  586.     // {{{ _parse()
  587.  
  588.     /**
  589.      * Parse a cleaned and unfolded array of RFC2822 style header lines into a 'header array' with the header names as keys.
  590.      * When header names a'pear more the once, the resulting array will have the values nested in the order of a'pear'ence.
  591.      * 
  592.      * @param array $array RFC2822 style header lines (CRLF not included)
  593.      * @param optional $flags 
  594.      *
  595.      * @return array 'header array' with the header names as keys, values may be nested.
  596.      * @access private
  597.      * @since 0.1
  598.      */
  599.     function _parse($array$flags)
  600.     {
  601.     // Init return variable
  602.     $return = array();
  603.  
  604.     // Loop through all headers
  605.         foreach ($array as $field{
  606.         // Separate header name and value
  607.         if (!preg_match('/([\S]+)\:\s*(.*)\s*/'$field$matches)) {
  608.         // Fail...
  609.         }
  610.         $name $matches[1];
  611.         $value $matches[2];
  612.         unset($matches);
  613.  
  614.         // Change header name to lower case
  615.         if (($flags NET_NNTP_HEADER_SET_KEEPCASE!= NET_NNTP_HEADER_SET_KEEPCASE{
  616.          $name strtolower($name);
  617.         }
  618.         
  619.         // Decode header value acording to RFC 2047
  620.         if (($flags NET_NNTP_HEADER_SET_DECODE== NET_NNTP_HEADER_SET_UNFOLD{
  621.         $value $this->decodeString($value);
  622.         }
  623.         
  624.         // Add header to $return array
  625.             if (isset($return[$name]AND is_array($return[$name])) {
  626.         // The header name has already been used at least two times.
  627.                 $return[$name][$value;
  628.             elseif (isset($return[$name])) {
  629.         // The header name has already been used one time -> change to nedted values.
  630.                 $return[$name= array($return[$name]$value);
  631.             else {
  632.         // The header name has not used until now.
  633.             $return[$name$value;
  634.             }
  635.         }
  636.  
  637.         return $return;
  638.     }
  639.  
  640.     // }}}
  641.     // {{{ _regenerateString()
  642.     
  643.     /**
  644.      * Generate a string of RFC2822 style header lines from the 'header array' given in $array.
  645.      * 
  646.      * @param array $array RFC2822 style header lines
  647.      * @param optional $flags 
  648.      *
  649.      * @return string RFC822 style header lines (CRLF included).
  650.      * @access private
  651.      * @since 0.1
  652.      */
  653.     function _regenerateString($array$flags)
  654.     {
  655.     // ( Forward to _regenerateArray() and then convert to string )
  656.     return implode("\r\n"$this->_regenerateArray($array$flags));
  657.     }
  658.  
  659.     // }}}
  660.     // {{{ _regenerateArray()
  661.  
  662.     /**
  663.      * Generate an array of RFC2822 style header lines from the array given in $array.
  664.      *
  665.      * @param array $array 'header field array'
  666.      * @param optional $flags 
  667.      *
  668.      * @return array RFC822 style header lines (CRLF not included).
  669.      * @access private
  670.      * @since 0.1
  671.      */
  672.     function _regenerateArray($array$flags)
  673.     {
  674.     // Init return variable
  675.     $return = array();
  676.  
  677.     // Loop through headers
  678.         foreach ($array as $name => $value{
  679.         // Encode header values acording to RFC 2047
  680.         if (($flags NET_NNTP_HEADER_GET_ENCODE== NET_NNTP_HEADER_GET_ENCODE{
  681.         if (is_array($value)) {
  682.             foreach(array_keys($valueas $key{
  683.             $value[$key$this->encodeString($value[$key]);
  684.             }
  685.         else {
  686.             $value $this->encodeString($value);
  687.         }
  688.         }
  689.  
  690.         if (is_array($value)) {
  691.             foreach ($value as $sub_value{
  692.                 $return[$name.': '.$sub_value;
  693.         }
  694.         else {
  695.             $return[$name.': '.$value;
  696.         }
  697.         }
  698.  
  699.     // Fold headers
  700.     if (($flags NET_NNTP_HEADER_GET_FOLD== NET_NNTP_HEADER_GET_FOLD{
  701.         $return $this->foldArray($return);
  702.     }
  703.  
  704.         return $return;
  705.     }
  706.  
  707.     // }}}
  708.     // {{{ unfoldString()
  709.  
  710.     /**
  711.      * Do the (RFC822 3.1.1) header unfolding to a string of RFC2822 header lines.
  712.      * 
  713.      * @param string $string RFC2822 header lines to unfolded (CRLF included)
  714.      *
  715.      * @return string Unfolded RFC2822 header lines (CRLF included)
  716.      * @access public
  717.      * @since 0.1
  718.      */
  719.     function unfoldString($string)
  720.     {
  721.     // Correct \r to \r\n
  722.         $string preg_replace("/\r?\n/""\r\n"$string);
  723.  
  724.     // Unfold multiline headers
  725.         $string preg_replace("/\r\n(\t| )+/"' '$string);
  726.  
  727.     return $string;
  728.     }
  729.  
  730.     // }}}
  731.     // {{{ unfoldArray()
  732.  
  733.     /**
  734.      * Do the (RFC822 3.1.1) header unfolding to an array of RFC2822 header lines.
  735.      *
  736.      * @param array $array RFC2822 header lines to unfolded (CRLF not included)
  737.      *
  738.      * @return array Unfolded RFC2822 header lines (CRLF not included)
  739.      * @access public
  740.      * @since 0.1
  741.      */
  742.     function unfoldArray($array)
  743.     {
  744.     // Unfold multiline headers
  745.     for ($i count($array)-1; $i>0; $i--{
  746.  
  747.         // Check for leading whitespace
  748.         if (preg_match('/^(\x09|\x20)/'$array[$i])) {
  749.             
  750.             // Remove folding \r\n
  751.                 if (substr($array[$i-1]-2== "\r\n"{
  752.                 $array[$i-1substr($array[$i-1]0-2);
  753.                 }
  754.             
  755.             // Append folded line to prev line
  756.             $array[$i-1$array[$i-1].' '.ltrim($array[$i]" \t");
  757.             
  758.             // Remove folded line
  759.         array_splice($array$i1);
  760.         }
  761.     }
  762.  
  763.     return $array;
  764.     }
  765.  
  766.     // }}}
  767.     // {{{ foldArray()
  768.  
  769.     /**
  770.      * Folds an array of RFC2822 style header lines.
  771.      *
  772.      * @param array $array 
  773.      * @param optional int $maxlen
  774.      *
  775.      * @return array 
  776.      * @access public
  777.      * @since 0.1
  778.      */
  779.     function foldArray($array$maxlen = 78)
  780.     {
  781.     $return = array();
  782.  
  783.     foreach (array_keys($arrayas $key{
  784.         $tmp $this->_foldExplode($array[$key]$maxlen);
  785.         $prepend '';
  786.         foreach (array_keys($tmpas $key2{
  787.         $return[$prepend.$tmp[$key2];
  788.         $prepend "\t";
  789.         }
  790.     }
  791.  
  792.     return $return;    
  793.     }
  794.  
  795.     // }}}
  796.     // {{{ foldString()
  797.  
  798.     /**
  799.      * Folds a string by inserting CRLF's and TAB's where allowed
  800.      *
  801.      * @param string $string 
  802.      * @param optional int $maxlen
  803.      *
  804.      * @return string 
  805.      * @access public
  806.      * @since 0.1
  807.      */
  808.     function foldString($string$maxlen = 78)
  809.     {
  810.     $array $this->_foldExplode($string$maxlen);
  811.     $return implode("\r\n\t"$array);
  812.     return $return;
  813.     }
  814.  
  815.     // }}}
  816.     // {{{ _foldExplode()
  817.  
  818.     /**
  819.      * Unfold $string, and return a 'folded' array
  820.      *
  821.      * The current implementation is still experimental, and is NOT expected to comply with RFC2822 !!!
  822.      *
  823.      * @param string $string 
  824.      * @param optional int $maxlen
  825.      *
  826.      * @return array 
  827.      * @access private
  828.      * @since 0.1
  829.      */
  830.     function _foldExplode($string$maxlen = 78)
  831. //TODO:
  832.     {
  833.     if ($maxlen < 20{
  834.         $maxlen = 20;
  835.     }
  836.  
  837.     if ($maxlen > 998{
  838.         $maxlen = 998;
  839.     }
  840.  
  841.     if (strlen($string<= $maxlen{
  842.         return array($string);
  843.         }
  844.       
  845.     $min = (int) ($maxlen (2/5)) - 4;
  846.         $max $maxlen - 5;                   // 4 for leading spcs + 1 for [\,\;]
  847.  
  848.     // try splitting at ',' or ';'   >2/5 along the line
  849.         // Split the line up
  850.     // next split a whitespace
  851.     // else we are looking at a single word and probably don't want to split
  852.     $exp = array();
  853.         $exp[= "[^\"]\{$min,$max}?[\,\;]\s";
  854.         $exp[= "[^\"]\{1,$max}\s";
  855.         $exp["[^\s\"]*(?:\"[^\"]*\"[^\s\"]*)+\s";
  856.     $exp["[^\s\"]+\s";
  857.  
  858.     $exp ="/^\s*(".implode('|'$exp).")(.*)\$/x";
  859.     $tmp $string;
  860.     $return = array();
  861.  
  862.     while ((strlen($tmp$max&& (preg_match($exp$tmp$match))) {
  863.         $return[$match[1];
  864.         $tmp $match[2];
  865.     }
  866.  
  867.     $return[$tmp;
  868.     
  869.     return $return;
  870.     }
  871.  
  872.     // }}}
  873.     // {{{ decodeString()
  874.  
  875.     /**
  876.      * Given a header/string, this function will decode it according to RFC2047.
  877.      * Probably not *exactly* conformant, but it does pass all the given
  878.      * examples (in RFC2047).
  879.      * 
  880.      * @param string $input Input header value to decode
  881.      *
  882.      * @return string Decoded header value
  883.      * @access public
  884.      * @since 0.1
  885.      */
  886.     function decodeString($input)
  887.     {
  888.         // Remove white space between encoded-words
  889.         $input preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i''\1=?'$input);
  890.  
  891.         // For each encoded-word...
  892.         while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i'$input$matches)) {
  893.  
  894.             $encoded  $matches[1];
  895.             $charset  $matches[2];
  896.             $encoding $matches[3];
  897.             $text     $matches[4];
  898.  
  899.             switch (strtolower($encoding)) {
  900.  
  901.                 case 'b'// RFC2047 4.1
  902.                     $text base64_decode($text);
  903.                     break;
  904.  
  905.                 case 'q'// RFC2047 4.2
  906.                     $text str_replace('_'' '$text);
  907.                     preg_match_all('/=([a-f0-9]{2})/i'$text$matches);
  908.                     foreach($matches[1as $value)
  909.                         $text str_replace('='.$valuechr(hexdec($value))$text);
  910.                     break;
  911.             }
  912.  
  913.             $input str_replace($encoded$text$input);
  914.         }
  915.  
  916.         return $input;
  917.     }
  918.  
  919.     // }}}
  920.     // {{{ encodeString()
  921.  
  922.     /**
  923.      * Encodes the string given in $string as per RFC2047
  924.      * 
  925.      * @param string $string The string to encode
  926.      *
  927.      * @return string Encoded string
  928.      * @access public
  929.      * @since 0.1
  930.      */
  931.     function encodeString($string)
  932.     {
  933.     // TODO: could be better! (Look into CPAN's Encode::MIME::Header)
  934.     
  935.     $charset 'iso-8859-1';
  936.     
  937.         preg_match_all('/(\w*[\x80-\xFF]+\w*)/'$string$matches);
  938.     foreach ($matches[1as $value{
  939.             $replacement preg_replace('/([\x80-\xFF])/e''"=" . strtoupper(dechex(ord("\1")))'$value);
  940.             $string str_replace($value'=?' $charset '?Q?' $replacement '?='$string);
  941.         }
  942.             
  943.         return $string;
  944.     }
  945.  
  946.     // }}}
  947.     // {{{ cleanString()
  948.  
  949.     /**
  950.      * Removes CRLF and misplaced empty lines before and after actual headerlines.
  951.      * 
  952.      * @param string $string. 
  953.      *
  954.      * @return string 
  955.      * @access public
  956.      * @since 0.1
  957.      */
  958.     function cleanString($string)
  959.     {
  960.     // Correct missing CR's before LF's
  961.         $string preg_replace("!\r?\n!""\r\n"$string);
  962.  
  963.     // Remove empty lines from start and end.
  964.     // TODO: This should be done better...
  965.     $string trim($string"\r\n");
  966.  
  967.         return $string;
  968.     }
  969.  
  970.     // }}}
  971.     // {{{ cleanArray()
  972.  
  973.     /**
  974.      * Removes CRLF and misplaced empty lines before and after actual headerlines.
  975.      * 
  976.      * @param array $input 
  977.      *
  978.      * @return array 
  979.      * @access public
  980.      * @since 0.1
  981.      */
  982.     function cleanArray($input)
  983.     {
  984.     // Remove empty lines from the start
  985.     while (reset($input== "\r\n"{
  986.         array_shift($input);
  987.     }
  988.     // Remove empty lines from the end
  989.     while (end($input== "\r\n"{
  990.         array_pop($input);
  991.     }
  992.  
  993.     // Run backwards through all lines
  994.     for ($i count($input)-1; $i > 0; $i--{
  995.  
  996.         // Remove \r\n from the end
  997.         $input preg_replace("/\r?\n$/"''$input);
  998.     }
  999.  
  1000.         return $input;
  1001.     }
  1002.  
  1003.     // }}}
  1004.  
  1005. }
  1006.  
  1007. // }}}
  1008.  
  1009. ?>

Documentation generated on Mon, 11 Mar 2019 14:30:58 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.