Completed
Branch 0.4 (9e6d2f)
by Zaahid
03:51
created

ConvertStreamFilter   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 80
Duplicated Lines 0 %

Test Coverage

Coverage 95.65%

Importance

Changes 0
Metric Value
wmc 9
eloc 27
dl 0
loc 80
ccs 22
cts 23
cp 0.9565
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A onCreate() 0 13 2
A getFilteredBucket() 0 14 5
A filter() 0 8 2
1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 * 
5
 * Idea taken from HHVM's ConvertFilter and coded to avoid requiring a
6
 * different license and because I don't want to deal with legalities.
7
 * 
8
 * Unfortunately the HHVM version seems to fail for larger base64-encoded files
9
 * (both encoding and decoding).  Once the stream needs to be buffered, if it
10
 * isn't buffered on a 3-byte chunk for encoding, or 4 byte-chunk for decoding,
11
 * it won't make sense.  Currently it is only used for quoted-printable encoding
12
 * and decoding.
13
 *
14
 * @license http://opensource.org/licenses/bsd-license.php BSD
15
 */
16
namespace ZBateson\MailMimeParser\Stream;
17
18
use php_user_filter;
19
20
class ConvertStreamFilter extends php_user_filter
21
{
22
    /**
23
     * Name used when registering with stream_filter_register.
24
     */
25
    const STREAM_FILTER_NAME = 'mmp-convert.*';
26
27
    /**
28
     * @var string Leftovers from the last incomplete line that was parsed, to
29
     *      be prepended to the next line read.
30
     */
31
    private $leftover = '';
32
    
33
    /**
34
     * @var string function to call for encoding/decoding
35
     */
36
    private $fnFilterName;
37
    
38
    /**
39
     * Sets up which function should be called.
40
     * 
41
     * @return bool
42
     */
43 62
    public function onCreate()
44
    {
45
        // strip off 'mmp-convert.'
46 62
        $name = substr($this->filtername, 12);
47
        $aFilters = [
48 62
            'quoted-printable-encode' => true,
49
            'quoted-printable-decode' => true,
50
        ];
51 62
        if (!isset($aFilters[$name])) {
52
            return false;
53
        }
54 62
        $this->fnFilterName = str_replace('-', '_', $name);
55 62
        return true;
56
    }
57
58
    /**
59
     * Sets up a remainder of read bytes if one of the last two bytes
60
     * read is an '=' since quoted_printable_decode wouldn't work if one
61
     * read operation ends with "=3" and the next begins with "D" for
62
     * example.
63
     *
64
     * @param string $data
65
     */
66 59
    private function getFilteredBucket($data)
67
    {
68 59
        $ret = $this->leftover . $data;
69 59
        if ($this->fnFilterName === 'quoted_printable_decode') {
70 59
            $len = strlen($ret);
71 59
            $eq = strrpos($ret, '=');
72 59
            if (($eq !== false) && ($eq === $len - 1 || $eq === $len - 2)) {
73 1
                $this->leftover = substr($ret, $eq);
74 1
                $ret = substr($ret, 0, $eq);
75
            } else {
76 59
                $this->leftover = '';
77
            }
78
        }
79 59
        return $ret;
80
    }
81
    
82
    /**
83
     * Filter implementation converts calls the relevant encode/decode filter
84
     * and chunk_split if needed, before returning PSFS_PASS_ON.
85
     * 
86
     * @param resource $in
87
     * @param resource $out
88
     * @param int $consumed
89
     * @param bool $closing
90
     * @return int
91
     */
92 59
    public function filter($in, $out, &$consumed, $closing)
93
    {
94 59
        while ($bucket = stream_bucket_make_writeable($in)) {
95 59
            $filtered = $this->getFilteredBucket($bucket->data);
96 59
            $data = call_user_func($this->fnFilterName, $filtered);
97 59
            stream_bucket_append($out, stream_bucket_new($this->stream, $data));
0 ignored issues
show
Bug Best Practice introduced by
The property stream does not exist on ZBateson\MailMimeParser\Stream\ConvertStreamFilter. Did you maybe forget to declare it?
Loading history...
98
        }
99 59
        return PSFS_PASS_ON;
100
    }
101
}