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

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