Completed
Pull Request — master (#267)
by Richard
08:54
created

AbstractMixer::getPartSize()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
nc 1
dl 0
loc 1
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * The RandomLib library for securely generating random numbers and strings in PHP
5
 *
6
 * @author     Anthony Ferrara <[email protected]>
7
 * @copyright  2011 The Authors
8
 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
9
 * @version    Build @@version@@
10
 */
11
12
/**
13
 * An abstract mixer to implement a common mixing strategy
14
 *
15
 * PHP version 5.3
16
 *
17
 * @category  PHPSecurityLib
18
 * @package   Random
19
 *
20
 * @author    Anthony Ferrara <[email protected]>
21
 * @copyright 2011 The Authors
22
 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
23
 *
24
 * @version   Build @@version@@
25
 */
26
namespace RandomLib;
27
28
use SecurityLib\Util;
29
30
/**
31
 * An abstract mixer to implement a common mixing strategy
32
 *
33
 * @see      http://tools.ietf.org/html/rfc4086#section-5.2
34
 *
35
 * @category PHPSecurityLib
36
 * @package  Random
37
 *
38
 * @author   Anthony Ferrara <[email protected]>
39
 */
40
abstract class AbstractMixer implements \RandomLib\Mixer
41
{
42
43
    /**
44
     * Get the block size (the size of the individual blocks used for the mixing)
45
     *
46
     * @return int The block size
47
     */
48
    abstract protected function getPartSize();
49
50
    /**
51
     * Mix 2 parts together using one method
52
     *
53
     * @param string $part1 The first part to mix
54
     * @param string $part2 The second part to mix
55
     *
56
     * @return string The mixed data
57
     */
58
    abstract protected function mixParts1($part1, $part2);
59
60
    /**
61
     * Mix 2 parts together using another different method
62
     *
63
     * @param string $part1 The first part to mix
64
     * @param string $part2 The second part to mix
65
     *
66
     * @return string The mixed data
67
     */
68
    abstract protected function mixParts2($part1, $part2);
69
70
    /**
71
     * Mix the provided array of strings into a single output of the same size
72
     *
73
     * All elements of the array should be the same size.
74
     *
75
     * @param array $parts The parts to be mixed
76
     *
77
     * @return string The mixed result
78
     */
79
    public function mix(array $parts)
80
    {
81
        if (empty($parts)) {
82
            return '';
83
        }
84
        $len        = Util::safeStrlen($parts[0]);
85
        $parts      = $this->normalizeParts($parts);
86
        $stringSize = count($parts[0]);
87
        $partsSize  = count($parts);
88
        $result     = '';
89
        $offset     = 0;
90
        for ($i = 0; $i < $stringSize; $i++) {
91
            $stub = $parts[$offset][$i];
92
            for ($j = 1; $j < $partsSize; $j++) {
93
                $newKey = $parts[($j + $offset) % $partsSize][$i];
94
                //Alternately mix the output for each source
95
                if ($j % 2 == 1) {
96
                    $stub ^= $this->mixParts1($stub, $newKey);
97
                } else {
98
                    $stub ^= $this->mixParts2($stub, $newKey);
99
                }
100
            }
101
            $result .= $stub;
102
            $offset  = ($offset + 1) % $partsSize;
103
        }
104
105
        return Util::safeSubstr($result, 0, $len);
106
    }
107
108
    /**
109
     * Normalize the part array and split it block part size.
110
     *
111
     * This will make all parts the same length and a multiple
112
     * of the part size
113
     *
114
     * @param array $parts The parts to normalize
115
     *
116
     * @return array The normalized and split parts
117
     */
118
    protected function normalizeParts(array $parts)
119
    {
120
        $blockSize = $this->getPartSize();
121
        $callback  = function ($value) {
122
            return Util::safeStrlen($value);
123
        };
124
        $maxSize = max(array_map($callback, $parts));
125
        if ($maxSize % $blockSize != 0) {
126
            $maxSize += $blockSize - ($maxSize % $blockSize);
127
        }
128
        foreach ($parts as &$part) {
129
            $part = $this->str_pad($part, $maxSize, chr(0));
130
            $part = str_split($part, $blockSize);
131
        }
132
133
        return $parts;
134
    }
135
136
    private function str_pad($string, $size, $character)
137
    {
138
        $start = Util::safeStrlen($string);
139
        $inc = Util::safeStrlen($character);
140
        for ($i = $start; $i < $size; $i+= $inc) {
141
            $string = $string . $character;
142
        }
143
144
        return Util::safeSubstr($string, 0, $size);
145
    }
146
147
    private function str_split($string, $size)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
148
    {
149
        $blocks = array();
150
        $length = Util::safeStrlen($string);
151
        $parts = ceil($length / $size);
152
        for ($i = 0; $i < $parts; $i++) {
153
            $blocks[] = Util::safeSubstr($string, $i * $length, $length);
154
        }
155
156
        return $blocks;
157
    }
158
}
159