Completed
Push — master ( 147214...53e4d6 )
by Zaahid
09:05
created

Base64EncodeStreamFilter::filter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 4
crap 1
1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace ZBateson\MailMimeParser\Stream;
8
9
use php_user_filter;
10
11
/**
12
 * Unfortunately neither the built-in base64 encoder in PHP, nor the HHVM
13
 * implementation for their ConvertFilter seem to handle large streams
14
 * correctly.  There appears to be no provision for data coming in when they're
15
 * not split on 3 byte-chunks (each 3-byte chunk trnaslates to 4-bytes of base64
16
 * encoded data).
17
 * 
18
 * @author Zaahid Bateson
19
 */
20
class Base64EncodeStreamFilter extends php_user_filter
21
{
22
    /**
23
     * Name used when registering with stream_filter_register.
24
     */
25
    const STREAM_FILTER_NAME = 'convert.base64-encode';
26
    
27
    /**
28
     * @var int number of bytes written for chunk-splitting
29
     */
30
    private $numBytesWritten = 0;
31
    
32
    /**
33
     * @var StreamLeftover
34
     */
35
    private $leftovers;
36
    
37
    /**
38
     * Base64-encodes the passed $data string and appends it to $out.
39
     * 
40
     * @param string $data data to convert
41
     * @param resource $out output bucket stream
42
     */
43 33
    private function convertAndAppend($data, $out)
44
    {
45 33
        $converted = base64_encode($data);
46 33
        $numBytes = strlen($converted);
47 33
        if ($this->numBytesWritten != 0) {
48 2
            $next = 76 - ($this->numBytesWritten % 76);
49 2
            $converted = substr($converted, 0, $next) . "\r\n" . rtrim(chunk_split(substr($converted, $next)));
50 2
        } else {
51 33
            $converted = rtrim(chunk_split($converted));
52
        }
53 33
        $this->numBytesWritten += $numBytes;
54 33
        stream_bucket_append($out, stream_bucket_new($this->stream, $converted));
1 ignored issue
show
Bug introduced by
The property stream does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
55 33
    }
56
    
57
    /**
58
     * Reads from the input bucket stream, converts, and writes the uuencoded
59
     * stream to $out.
60
     * 
61
     * @param resource $in input bucket stream
62
     * @param resource $out output bucket stream
63
     * @param int $consumed incremented by number of bytes read from $in
64
     */
65 33
    private function readAndConvert($in, $out, &$consumed)
66
    {
67 33
        while ($bucket = stream_bucket_make_writeable($in)) {
68 33
            $data = $this->leftovers->value . $bucket->data;
69 33
            $consumed += $bucket->datalen;
70 33
            $nRemain = strlen($data) % 3;
71 33
            $toConvert = $data;
72 33
            if ($nRemain === 0) {
73 2
                $this->leftovers->value = '';
74 2
                $this->leftovers->encodedValue = '';
75 2
            } else {
76 33
                $this->leftovers->value = substr($data, -$nRemain);
77 33
                $this->leftovers->encodedValue = base64_encode($this->leftovers->value) . "\r\n";
78 33
                $toConvert = substr($data, 0, -$nRemain);
79
            }
80 33
            $this->convertAndAppend($toConvert, $out);
81 33
        }
82 33
    }
83
    
84
    /**
85
     * Filter implementation converts encoding before returning PSFS_PASS_ON.
86
     * 
87
     * @param resource $in
88
     * @param resource $out
89
     * @param int $consumed
90
     * @param bool $closing
91
     * @return int
92
     */
93 33
    public function filter($in, $out, &$consumed, $closing)
94
    {
95 33
        $this->readAndConvert($in, $out, $consumed);
96 33
        return PSFS_PASS_ON;
97
    }
98
    
99
    /**
100
     * Sets up the leftovers object
101
     */
102 33
    public function onCreate()
103
    {
104 33
        if (isset($this->params['leftovers'])) {
105 33
            $this->leftovers = $this->params['leftovers'];
106 33
        } else {
107
            $this->leftovers = new StreamLeftover();
108
        }
109 33
    }
110
}
111