Beispiel #1
0
 /**
  * Encodes a string
  *
  * @param mixed $value The value to encode
  * @return mixed The result of the encoding process
  */
 public function to($string)
 {
     // Yes, I realize that the iconv methods can handle this, but this method
     // can do one thing the iconv encode method cant: Handle encoding without
     // a header defined
     $string = (string) $string;
     // React to the input encoding
     $string = iconv($this->getInputEncoding(), $this->getOutputEncoding(), $string);
     // Generate the part that describes the encoding
     $encodingPart = "=?" . $this->getOutputEncoding() . "?B?";
     // Do the actual encoding
     $string = base64_encode($string);
     // If we aren't doing any wrapping, take the easy out
     if ($this->getLineLength() == FALSE) {
         return ($this->headerExists() ? $this->getHeader() . ": " : "") . $encodingPart . $string . "?=";
     }
     // If there is a header to attach, then we need to figure out how many
     // characters will fit on the first line with it
     if ($this->headerExists()) {
         // If the header is so long it won't fit on a line (plus one for the colon)
         if ($this->getLineLength() < strlen($this->getHeader()) + 1) {
             $err = new \r8\Exception\Data($this->getHeader(), "MIME Header", "Header length exceeds the maximum line length");
             $err->addData("Max Line Length", $this->getLineLength());
             throw $err;
         }
         // Line length, minus the Header length, minus two for the colon and
         // space, minus the length of the encoding definition, minus two for
         // the trailing ?=
         $firstLineLength = $this->getLineLength() - strlen($this->getHeader()) - 2 - strlen($encodingPart) - 2;
         // Force it to a multiple of 4
         $firstLineLength = floor($firstLineLength / 4) * 4;
         $prepend = $this->getHeader() . ":";
         // If there is room on the first line for at least four characters,
         // then add them on
         if ($firstLineLength > 0) {
             $prepend .= " " . $encodingPart . substr($string, 0, $firstLineLength) . "?=";
             $string = substr($string, $firstLineLength);
             // If it all fits on the first line, lets get out of here
             if ($string == "") {
                 return $prepend;
             }
         }
         $prepend .= $this->getEOL() . "\t" . $encodingPart;
     } else {
         $prepend = $encodingPart;
     }
     // The line length, minus one to compensate for the leading fold, minus
     // the length of the encoding definition, minus two for the trailing ?=
     $lineLength = $this->getLineLength() - 1 - strlen($encodingPart) - 2;
     // Force it to a multiple of four
     $lineLength = floor($lineLength / 4) * 4;
     // If the required data won't fit on a line, throw an error
     if ($lineLength <= 0) {
         throw new \r8\Exception\Data($this->getLineLength(), "Max Line Length", "Required content length exceeds the maximum line length");
     }
     return $prepend . implode("?=" . $this->getEOL() . "\t" . $encodingPart, str_split($string, $lineLength)) . "?=";
 }
Beispiel #2
0
 /**
  * Decodes an encoded string
  *
  * @param mixed $value The value to decode
  * @return mixed The original, unencoded value
  */
 public function from($string)
 {
     $string = trim((string) $string);
     $string = \r8\str\stripHead($string, "<~");
     $string = \r8\str\stripTail($string, "~>");
     $length = strlen($string);
     $result = "";
     $tuple = 0;
     $j = 0;
     // Loop over each character in the input
     for ($i = 0; $i < $length; $i++) {
         $chr = $string[$i];
         if ($j != 0 && ($chr == "z" || $chr == "y")) {
             $err = new \r8\Exception\Data($chr, "Unexpected Character", "Misplaced compression character");
             $err->addData("Encoded String", $string);
             throw $err;
         }
         switch ($chr) {
             // Add this character to the tuple
             default:
                 // Grab the character code and ensure it is a valid character
                 $ord = ord($chr) - 33;
                 if ($ord < 0 || $ord > 84) {
                     $err = new \r8\Exception\Data($chr, "Invalid Character", "Invalid encoding character");
                     $err->addData("Encoded String", $string);
                     throw $err;
                 }
                 // Integrate this character into the tuple
                 $tuple += $ord * pow(85, 4 - $j);
                 // If this isn't the last character in the tuple, move on
                 if ($j < 4 && $i != $length - 1) {
                     $j++;
                 } else {
                     // Compensate for an incomplete trailing tuple
                     if ($j < 4) {
                         for ($k = $j; $k <= 3; $k++) {
                             $tuple += 85 * pow(85, 3 - $k);
                         }
                     }
                     // Convert the 32bit integer to binary form
                     $tuple = str_pad(decbin($tuple), 32, "0", STR_PAD_LEFT);
                     // Split the binary into 8 bit segments and convert each back to an integer
                     $tuple = array_map("bindec", str_split($tuple, 8));
                     if ($j < 4) {
                         $tuple = array_slice($tuple, 0, $j);
                     }
                     // Convert each int into a character, then combine them
                     $result .= implode("", array_map("chr", $tuple));
                     // Reset the tuple to prepare for the next substring
                     $tuple = 0;
                     $j = 0;
                 }
                 break;
                 // Handle z compression
             // Handle z compression
             case "z":
                 $result .= chr(0) . chr(0) . chr(0) . chr(0);
                 break;
                 // Handle y compression
             // Handle y compression
             case "y":
                 $result .= "    ";
                 break;
                 // Skip over white space
             // Skip over white space
             case "\n":
             case "\r":
             case "\t":
             case " ":
             case "":
             case "\f":
             case "":
                 break;
         }
     }
     return $result;
 }
Beispiel #3
0
 /**
  * Renders the template and returns it as a string
  *
  * @return String Returns the rendered template as a string
  */
 public function render()
 {
     $self = $this;
     return preg_replace_callback($this->search, function ($matches) use($self) {
         // Ensure that the search string returns the proper number of matches
         if (count($matches) < 4) {
             $err = new \r8\Exception\Data($self->search, "Search Regular Expression", "Must return at least 3 groupings");
             $err->addData("Groupings", count($matches) - 1);
             throw $err;
         }
         // Handle escaped replace strings
         if (strlen($matches[1]) % 2 != 0) {
             return substr($matches[1], 0, -1) . $matches[2];
         } else {
             if (!$self->exists($matches[3]) || $self->get($matches[3]) === $self) {
                 return $matches[1];
             } else {
                 return $matches[1] . (string) $self->get($matches[3]);
             }
         }
     }, $this->template);
 }
Beispiel #4
0
 /**
  * Encodes a string
  *
  * @param mixed $value The value to encode
  * @return mixed The result of the encoding process
  */
 public function to($string)
 {
     // Yes, I realize that the iconv methods can handle this, but this method
     // can do a few things the iconv encode method cant: Handle encoding without
     // a header defined, use the underscore as spaces to save on space.
     $string = (string) $string;
     // React to the input encoding
     $string = iconv($this->getInputEncoding(), $this->getOutputEncoding(), $string);
     // This will hold the resulting string
     $result = "";
     // Generate the part that describes the encoding
     $encodingPart = "=?" . $this->getOutputEncoding() . "?Q?";
     // This is a running total of the length of the current line
     // Once this reaches the max length, the line will be wrapped
     $currentLine = 0;
     if ($this->headerExists()) {
         $result = $this->headerExists() ? $this->getHeader() . ":" : "";
         // If the header is so long it won't fit on a line (plus one for the colon)
         if ($this->getLineLength() !== FALSE && $this->getLineLength() < strlen($result) + 1) {
             $err = new \r8\Exception\Data($this->getHeader(), "MIME Header", "Header length exceeds the maximum line length");
             $err->addData("Max Line Length", $this->getLineLength());
             throw $err;
         }
         // If the encoding part and the header can't fit on the same line,
         // plus one for the space that hasn't been added yet,  plus two for the trailing '?=',
         // plus 3 for the length of a single encoded character
         if ($this->getLineLength() !== FALSE && strlen($result) + strlen($encodingPart) + 1 + 2 + 3 > $this->getLineLength()) {
             $result .= $this->getEOL() . "\t";
         } else {
             $result .= " ";
             // Adjust the offset of the current line to compensate for the length of the header
             $currentLine += strlen($result) - 1;
         }
     }
     if ($this->getLineLength() === FALSE) {
         $maxLineLength = FALSE;
     } else {
         // The max line length is the line length, minus one for the fold,
         // minus the length of the encoding definition, minus two for the closing ?=
         $maxLineLength = $this->getLineLength() - 1 - strlen($encodingPart) - 2;
     }
     if ($maxLineLength !== FALSE && $maxLineLength <= 0) {
         throw new \r8\Exception\Data($this->getLineLength(), "Max Line Length", "Required content length exceeds the maximum line length");
     }
     // Attach the leading encoding info
     $result .= $encodingPart;
     // Grab the string length only once
     $stringLength = strlen($string);
     // Iterate over each character of the string we're encoding
     for ($i = 0; $i < $stringLength; $i++) {
         // Replace spaces with underscores
         if ($string[$i] == " ") {
             $result .= "_";
             $currentLine++;
         } else {
             if (ord($string[$i]) <= 32 || ord($string[$i]) >= 127 || $string[$i] == "=" || $string[$i] == "?" || $string[$i] == "_" || $string[$i] == ":") {
                 $result .= "=" . strtoupper(str_pad(dechex(ord($string[$i])), 2, "0", STR_PAD_LEFT));
                 $currentLine += 3;
             } else {
                 $result .= $string[$i];
                 $currentLine++;
             }
         }
         if ($maxLineLength !== FALSE) {
             // If we have reached the max characters in a line, and this isn't
             // the final character in the string, then wrap
             if ($currentLine >= $maxLineLength && $i != $stringLength - 1) {
                 $result .= "?=" . $this->getEOL() . "\t" . $encodingPart;
                 $currentLine = 0;
             }
         }
     }
     return $result . "?=";
 }