Completed
Push — master ( 6de7b0...43bdbb )
by smiley
04:41
created

Base32::toString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
/**
3
 * class.Base32.php5
4
 * Provide Base32 conversion class
5
 *
6
 * @author    Shannon Wynter {@link http://fremnet.net/contact}
7
 * @version   0.4
8
 * @copyright Copyright &copy; 2006 Shannon Wynter
9
 * @link      http://fremnet.net
10
 *
11
 * Class to provide base32 encoding/decoding of strings
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 *
27
 * ChangeLog
28
 * -----------
29
 * version 0.4, 2016-02-29, smiley {@link https://github.com/codemasher}
30
 *  - cleanup
31
 *  - separated character set class
32
 * version 0.3, 2015-12-06, smiley {@link https://github.com/codemasher}
33
 *  - static all the things!
34
 * version 0.2, 2008-08-07, Shannon Wynter {@link http://fremnet.net/contact}
35
 *  - Fixed transposition of Y and Z in csRFC3548
36
 * version 0.1, 2006-06-22, Shannon Wynter {@link http://fremnet.net/contact}
37
 *  - Initial release
38
 *
39
 * Notes
40
 * -----------
41
 * For dealing with humans it's probably best to use csSafe rather then csRFC3548
42
 *
43
 */
44
45
namespace chillerlan\Base32;
46
47
/**
48
 * Class Base32
49
 *
50
 * Provides Base32 conversion
51
 *
52
 */
53
class Base32{
54
55
	/**
56
	 * charset
57
	 *
58
	 * Internal holder of the current character set.
59
	 *
60
	 * @access protected
61
	 * @var string
62
	 */
63
	public static $charset = Base32Characters::RFC3548;
64
65
	/**
66
	 * setCharset
67
	 *
68
	 * Used to set the internal _charset variable
69
	 * I've left it so that people can arbirtrarily set their
70
	 * own charset
71
	 *
72
	 * @param string $charset The character set you want to use
73
	 *
74
	 * @throws \chillerlan\Base32\Base32Exception
75
	 */
76
	public static function setCharset($charset = Base32Characters::RFC3548){
77
		if(strlen($charset) === 32){
78
			self::$charset = strtoupper($charset);
79
		}
80
		else{
81
			throw new Base32Exception('Length must be exactly 32');
82
		}
83
	}
84
85
	/**
86
	 * str2bin
87
	 *
88
	 * Converts any ascii string to a binary string
89
	 *
90
	 * @param string $str The string you want to convert
91
	 *
92
	 * @return string String of 0's and 1's
93
	 */
94
	public static function str2bin($str){
95
		$chrs = unpack('C*', $str);
96
97
		return vsprintf(str_repeat('%08b', count($chrs)), $chrs);
98
	}
99
100
	/**
101
	 * bin2str
102
	 *
103
	 * Converts a binary string to an ascii string
104
	 *
105
	 * @param string $str The string of 0's and 1's you want to convert
106
	 *
107
	 * @return string The ascii output
108
	 * @throws \chillerlan\Base32\Base32Exception
109
	 */
110
	public static function bin2str($str){
111
		self::checkLength($str);
112
		self::checkBin($str);
113
114
		preg_match_all('/.{8}/', $str, $chrs);
115
		$chrs = array_map('bindec', $chrs[0]);
116
117
		// I'm just being slack here
118
		array_unshift($chrs, 'C*');
119
120
		return call_user_func_array('pack', $chrs);
121
	}
122
123
	/**
124
	 * fromBin
125
	 *
126
	 * Converts a correct binary string to base32
127
	 *
128
	 * @param string $str The string of 0's and 1's you want to convert
129
	 *
130
	 * @return string String encoded as base32
131
	 * @throws \chillerlan\Base32\Base32Exception
132
	 */
133
	public static function fromBin($str){
134
		self::checkLength($str);
135
		self::checkBin($str);
136
137
		// Base32 works on the first 5 bits of a byte, so we insert blanks to pad it out
138
		$str = preg_replace('/(.{5})/', '000$1', $str);
139
140
		// We need a string divisible by 5
141
		$length = strlen($str);
142
		$rbits = $length&7;
143
144
		if($rbits > 0){
145
			// Excessive bits need to be padded
146
			$ebits = substr($str, $length - $rbits);
147
			$str = substr($str, 0, $length - $rbits).'000'.$ebits.str_repeat('0', 5 - strlen($ebits));
148
		}
149
150
		preg_match_all('/.{8}/', $str, $chrs);
151
152
		$chrs = array_map(function($str){
153
			return self::$charset[bindec($str)];
154
		}, $chrs[0]);
155
156
		return implode('', $chrs);
157
	}
158
159
	/**
160
	 * toBin
161
	 *
162
	 * Accepts a base32 string and returns an ascii binary string
163
	 *
164
	 * @param string $str The base32 string to convert
165
	 *
166
	 * @return string Ascii binary string
167
	 * @throws \chillerlan\Base32\Base32Exception
168
	 */
169
	public static function toBin($str){
170
		if(!preg_match('/^['.self::$charset.']+$/', $str)){
171
			throw new Base32Exception('Must match character set');
172
		}
173
174
		// Convert the base32 string back to a binary string
175
		$str = array_map(function ($chr){
176
			return sprintf('%08b', strpos(self::$charset, $chr));
177
		}, str_split($str));
178
179
		// Remove the extra 0's we added
180
		$str = preg_replace('/000(.{5})/', '$1', implode('', $str));
181
182
		// Unpad if nessicary
183
		$length = strlen($str);
184
		$rbits = $length&7;
185
186
		if($rbits > 0){
187
			$str = substr($str, 0, $length - $rbits);
188
		}
189
190
		return $str;
191
	}
192
193
	/**
194
	 * fromString
195
	 *
196
	 * Convert any string to a base32 string
197
	 * This should be binary safe...
198
	 *
199
	 * @param string $str The string to convert
200
	 *
201
	 * @return string The converted base32 string
202
	 */
203
	public static function fromString($str){
204
		return self::fromBin(self::str2bin($str));
205
	}
206
207
	/**
208
	 * toString
209
	 *
210
	 * Convert any base32 string to a normal sctring
211
	 * This should be binary safe...
212
	 *
213
	 * @param string $str The base32 string to convert
214
	 *
215
	 * @return string The normal string
216
	 */
217
	public static function toString($str){
218
		$str = strtoupper($str);
219
220
		// csSave actually has to be able to consider extra characters
221
		if(self::$charset === Base32Characters::CROCKFORD){
222
			$str = str_replace('O', '0', $str);
223
			$str = str_replace(['I', 'L'], '1', $str);
224
		}
225
226
		return self::bin2str(self::toBin($str));
227
	}
228
229
	/**
230
	 * @param $str
231
	 *
232
	 * @throws \chillerlan\Base32\Base32Exception
233
	 */
234
	protected static function checkLength($str){
235
		if(strlen($str) % 8 > 0){
236
			throw new Base32Exception('Length must be divisible by 8');
237
		}
238
	}
239
240
	/**
241
	 * @param $str
242
	 *
243
	 * @throws \chillerlan\Base32\Base32Exception
244
	 */
245
	protected static function checkBin($str){
246
		if(!preg_match('/^[01]+$/', $str)){
247
			throw new Base32Exception('Only 0 and 1 are permitted');
248
		}
249
	}
250
251
}
252