AESCBCStreamWriteCallBack::__set()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 2
1
<?php
2
require_once KS3_API_PATH.DIRECTORY_SEPARATOR."encryption".DIRECTORY_SEPARATOR."EncryptionUtil.php";
3
//下载
4
class AESCBCStreamWriteCallBack{
5
	private $iv;
6
	private $cek;
7
	private $contentLength;
8
	//数组,分别为上限和下限
9
	private $expectedRange;
10
	//经过调整后的range
11
	private $adjustedRange;
12
	//当前指针位置
13
	private $currentIndex;
14
	private $buffer;//上一次调用streaming_write_callback后,未解码的数据
15
	private $firstWrite = TRUE;
16
	public function __set($property_name, $value){
17
		$this->$property_name=$value;
18
	}
19
	public function __get($property_name){
20
		if(isset($this->$property_name))
21
		{
22
			return($this->$property_name);
23
		}else
24
		{
25
			return(NULL);
26
		}
27
	}
28
	//最后的数据大小肯定是blocksize的倍数,所以最后buffer中不会有未解密的内容。否则可以认为该文件是错误的
29
	public function streaming_write_callback($curl_handle,$data,$write_stream){
30
		$data = $this->buffer.$data;
31
32
		$length = strlen($data);
33
		//不能把上次的没读完的长度算在这次里,应该算在上次
34
		$written_total = 0-strlen($this->buffer);
35
		$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC);
36
		if($length<$blocksize)
37
			$this->buffer = $data;
38
		else{
39
			//如果期望的范围之后还有数据,则认为数据已经接收完毕。不做任何处理
40
			if($this->expectedRange["end"] < $this->expectedRange["start"]){
41
				return $written_total+strlen($data);
42
			}
43
			$this->buffer = substr($data,$length - $length%$blocksize);
44
			$data = substr($data,0,$length - $length%$blocksize);
45
		
46
			$ivoffset = 0;
47
			//range get时,如果不是从刚开始,则应该取加密后数据的前16个字节作为之后解密的iv
48
			if($this->firstWrite){
49
				$this->firstWrite = FALSE;
50
				if(!$this->isBegin()){
51
					$this->iv = substr($data,0,$blocksize);
52
					$data = substr($data,$blocksize);
53
					$ivoffset = $blocksize;
54
				}
55
				//初始化当前位置
56
				if(isset($this->adjustedRange))
57
					$this->currentIndex = $ivoffset+$this->adjustedRange["start"];
58
				else
59
					$this->currentIndex = $ivoffset;
60
			}
61
			$written_total+=$ivoffset;
62
			if(strlen($data) == 0){
63
				$decoded = "";
0 ignored issues
show
Unused Code introduced by
The assignment to $decoded is dead and can be removed.
Loading history...
64
				return $written_total;
65
			}else{
66
				$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,'');
67
				mcrypt_generic_init($td,$this->cek,$this->iv);
68
				$decoded = mdecrypt_generic($td,$data);
69
				mcrypt_generic_deinit($td);
70
				mcrypt_module_close($td);
71
			}
72
73
			$this->iv = substr($data,strlen($data)-$blocksize);
74
			//判断是否需要删除最后填充的字符,以及获取填充的字符
75
			$needRemovePad = FALSE;
76
			$pad = NULL;
77
78
			if($this->currentIndex+strlen($decoded) >=$this->contentLength){
79
				$needRemovePad = TRUE;
80
				$pad = ord(substr($decoded,strlen($decoded)-1,1));
81
				if($pad<=0||$pad>$blocksize)
82
				{
83
					//invalid pad
84
					$needRemovePad = FALSE;
85
				}
86
			}
87
88
			//将解密后的数据截取到期望的长度
89
			$startOffset = 0;
90
			$endOffset = 0;
91
			if(isset($this->expectedRange)){
92
				$trueEnd = $expectedEnd = $this->expectedRange["end"];
93
94
				if($this->currentIndex+strlen($decoded)>$expectedEnd){
95
					$preLength = strlen($decoded);
96
					$decoded = substr($decoded, 0,$expectedEnd-$this->currentIndex+1);
97
					$endOffset = $preLength-strlen($decoded);
98
				}else{
99
					//因为range是开始结束都计算的,range=1-2。currentIndex=1,长度是2,end=currentIndex+2-1
100
					$trueEnd = $this->currentIndex+strlen($decoded)-1; 
101
				}
102
				$expectedStart = $this->expectedRange["start"];
103
				if($this->currentIndex<$expectedStart){
104
					$decoded = substr($decoded,$expectedStart - $this->currentIndex);
105
					$startOffset = $expectedStart - $this->currentIndex;
106
				}
107
				//调整下次期望的开始
108
				$this->expectedRange["start"] = $trueEnd+1;
109
			}
110
111
			$padOffset = 0;
112
			//再次根据截取的长度判断是否需要删除最后填充的字符
113
			if($needRemovePad&&$endOffset > $pad){
114
				$needRemovePad = FALSE;
115
			}
116
			$actualWriteCount = 0;
117
			if($needRemovePad){
118
				$padOffset = $pad-$endOffset;
119
				$actualWriteCount = strlen($decoded)-$padOffset;
120
				if($actualWriteCount <= 0)//负数的情况就是用户期望的range里全是填充的
121
					$decoded = "";
122
				else
123
					$decoded = substr($decoded,0,strlen($decoded)-$padOffset);
124
			}
125
			$count = fwrite($write_stream, $decoded);
126
			if($count == 0)
127
				$count = $actualWriteCount;
128
			$count += $padOffset;
129
			$count += $startOffset;
130
			$count += $endOffset;
131
			$this->currentIndex += $count;
132
			$written_total+=$count;
133
		}
134
		//否则curl框架会报错
135
		$written_total+=strlen($this->buffer);
136
		return $written_total;
137
	}
138
	//是的话则使用初始化IV
139
	private function isBegin(){
140
		$beginIndex = 0;
141
		if(isset($this->adjustedRange["start"]))
142
			$beginIndex = $this->adjustedRange["start"];
143
		if($beginIndex == 0)
144
			return TRUE;
145
		else 
146
			return FALSE;
147
	}
148
}
149
//上传
150
class AESCBCStreamReadCallBack{
151
	private $iv;
152
	private $cek;
153
	private $contentLength;
154
	private $buffer;
155
	private $hasread = 0;
156
	private $mutipartUpload =FALSE;
157
	private $isLastPart = FALSE;
158
	public function __set($property_name, $value){
159
		$this->$property_name=$value;
160
	}
161
	public function __get($property_name){
162
		if(isset($this->$property_name))
163
		{
164
			return($this->$property_name);
165
		}else
166
		{
167
			return(NULL);
168
		}
169
	}
170
	public function streaming_read_callback($curl_handle,$file_handle,$length,$read_stream,$seek_position){
171
		// Once we've sent as much as we're supposed to send...
172
		if ($this->hasread >= $this->contentLength)
173
		{
174
			// Send EOF
175
			return '';
176
		}
177
		// If we're at the beginning of an upload and need to seek...
178
		if ($this->hasread == 0 && $seek_position>0 && $seek_position !== ftell($read_stream))
179
		{
180
			if (fseek($read_stream, $seek_position) !== 0)
181
			{
182
				throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.');
183
			}
184
		}
185
186
187
		$blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_ECB);
188
		$needRead = min($this->contentLength - $this->hasread,$length);
189
		$read = fread($read_stream,$needRead);
190
		$this->hasread += strlen($read);
191
		$isLast = FALSE;
192
		if($this->hasread >= $this->contentLength){
193
			$isLast = TRUE;
194
		}
195
		$data = $this->buffer.$read;
196
197
		$dataLength = strlen($data);
198
199
		if(!$isLast){
200
			$this->buffer = substr($data,$dataLength-$dataLength%$blocksize);
201
			$data = substr($data, 0,$dataLength-$dataLength%$blocksize);
202
		}else{
203
			//分块上传除最后一块外肯定是blocksize大小的倍数,所以不需要填充。
204
			if($this->mutipartUpload){
205
				if($this->isLastPart){
206
					$this->buffer = NULL;
207
					$data = EncryptionUtil::PKCS5Padding($data,$blocksize);
208
				}else{
209
					//donothing
210
				}
211
			}else{
212
				$this->buffer = NULL;
213
				$data = EncryptionUtil::PKCS5Padding($data,$blocksize);
214
			}
215
		}
216
		$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,'');
217
		mcrypt_generic_init($td,$this->cek,$this->iv);
218
		$encrypted = mcrypt_generic($td,$data);
219
		mcrypt_generic_deinit($td);
220
		//去除自动填充的16个字节//php的当恰好为16的倍数时竟然不填充?
221
		//$encrypted = substr($encrypted,0,strlen($encrypted)-$blocksize);
222
		//取最后一个block作为下一次的iv
223
		$this->iv = substr($encrypted, strlen($encrypted)-$blocksize);
224
		return $encrypted;
225
	}
226
}
227
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...