|
1 <?php
2
3 if (!class_exists('FastDFS', false)) {
4 define('FDFS_PROTO_PKG_LEN_SIZE', 8);
5 define('FDFS_PROTO_CMD_ACTIVE_TEST', 111);
6 define('FDFS_PROTO_CMD_RESP', 100);
7 define('FDFS_PROTO_CMD_UPLOAD_SLAVE_FILE', 21);
8 define('FDFS_PROTO_CMD_DELETE_FILE', 12);
9 define('FDFS_PROTO_CMD_GET_METADATA', 15);
10 define('FDFS_PROTO_CMD_SET_METADATA', 13);
11
12 //body_length + command + status
13 define('FDFS_HEADER_LENGTH', 10);
14 define('FDFS_IP_ADDRESS_SIZE', 16);
15 define('FDFS_FILE_EXT_NAME_MAX_LEN', 6);
16 define('FDFS_GROUP_NAME_MAX_LEN', 16);
17 define('FDFS_OVERWRITE_METADATA', 1);
18 define('FDFS_MERGE_METADATA', 2);
19
20 // 连接超时时间
21 define('FDFS_CONNECT_TIME_OUT', 5);
22 define('FDFS_FILE_PREFIX_MAX_LEN', 16);
23
24 //传输超时时间
25 define('FDFS_TRANSFER_TIME_OUT', 0);
26 define('FDFS_QUERY_STORE_WITHOUT_GROUP_ONE', 101);
27 define('FDFS_QUERY_STORE_WITH_GROUP_ONE', 104);
28
29 define('FDFS_TRACKER_QUERY_STORAGE_STORE_BODY_LEN', FDFS_GROUP_NAME_MAX_LEN + FDFS_IP_ADDRESS_SIZE + FDFS_PROTO_PKG_LEN_SIZE);
30
31 class FastDFS {
32
33 public $gConfig = array();
34
35 /**
36 *
37 * @var FastDFSTrackerClient
38 */
39 private $tracker;
40
41 /**
42 *
43 * @var FastDFSStorageClient
44 */
45 private $storage;
46 private $error = array(
47 'code' => 0,
48 'msg' => ''
49 );
50
51 /**
52 * 要使用这个类,你一定要在php的ini文件中进行fastdfs的配置
53 *
54 * @throws FastDFSException
55 */
56 public function __construct() {
57 $configFile = '';
58 $ini = parse_ini_file(php_ini_loaded_file());
59
60 if (!isset($ini['fastdfs_client.tracker_group_count'])) {
61 throw new FastDFSException("no define fastdfs config");
62 }
63 for ($i = 0; $i < $ini['fastdfs_client.tracker_group_count']; $i++) {
64 if (isset($ini['fastdfs_client.tracker_group' . $i])) {
65 $configFile = $ini['fastdfs_client.tracker_group' . $i];
66 break;
67 }
68 }
69 if (!file_exists($configFile)) {
70 throw new FastDFSException("client config $configFile not found");
71 }
72 $this->gConfig = parse_ini_file($configFile);
73 list($this->gConfig['tracker_host'], $this->gConfig['tracker_port']) = explode(':', $this->gConfig['tracker_server']);
74 }
75
76 /**
77 * 获得一个tracker
78 *
79 * @return \FastDFSTrackerClient
80 */
81 public function tracker_get_connection() {
82 $this->tracker = new FastDFSTrackerClient($this, $this->gConfig['tracker_host'], $this->gConfig['tracker_port']);
83
84 return $this->tracker;
85 }
86
87 /**
88 * 通过tracker获取一个stroage
89 *
90 * @param string $groupName 文件组名,当为空时,组名由tracker决定
91 * @param FastDFSTrackerClient $tracker
92 * @return \FastDFSStorageClient
93 */
94 public function tracker_query_storage_store($groupName, FastDFSTrackerClient $tracker) {
95 $this->storage = new FastDFSStorageClient($this, $groupName, $tracker);
96
97 return $this->storage;
98 }
99
100 /**
101 * 测试一下tracker服务器是否正常
102 *
103 * @param FastDFSTrackerClient $tracker
104 * @return boolean
105 */
106 public function active_test(FastDFSTrackerClient $tracker = null) {
107 $this->initTrackerAndStorage($tracker);
108
109 $header = self::packHeader(FDFS_PROTO_CMD_ACTIVE_TEST, 0);
110 $tracker->send($header);
111
112 $resHeader = self::parseHeader($tracker->read(FDFS_HEADER_LENGTH));
113
114 return $resHeader['status'] == 0 ? true : false;
115 }
116
117 public function get_last_error_no() {
118 return $this->error['code'];
119 }
120
121 public function add_error($errorNo, $info) {
122 $this->error['code'] = $errorNo;
123 $this->error['msg'] = $info;
124 }
125
126 public function get_last_error_info() {
127 return $this->error['msg'];
128 }
129
130 /**
131 * 在storage中删除一个文件
132 *
133 * @param string $groupName 文件所在的组名
134 * @param string $remoteFile 要删除的文件路径
135 * @param FastDFSStorageClient $tracker
136 * @param FastDFSStorageClient $storage
137 */
138 public function storage_delete_file($groupName, $remoteFile, FastDFSStorageClient $tracker, FastDFSStorageClient $storage) {
139 $this->initTrackerAndStorage($tracker, $storage, $groupName);
140
141 $this->storage->deleteFile($groupName, $remoteFile);
142 }
143
144 /**
145 * 往storage中上传一个文件
146 *
147 * @param string $localFile 你本地的文件路径
148 * @param string $extName 文件的扩展名,当名优提供扩展名时,会自动取文件的扩展名
149 * @param array $metas 文件的附加信息
150 * @param string $groupName 所在的组名,可以为空,为空时,由tracker决定
151 * @param FastDFSTrackerClient $tracker
152 * @param FastDFSStorageClient $storage
153 */
154 public function storage_upload_by_filename($localFile, $extName = '', $metas = array(), $groupName = '', FastDFSTrackerClient $tracker = null, FastDFSStorageClient $storage = null) {
155 $this->initTrackerAndStorage($tracker, $storage, $groupName);
156
157 return $this->storage->uploadByFilename($localFile, $extName, $metas);
158 }
159
160 /**
161 * 上传一个文件的附属文件,主要使用一个图片有缩略图的情况下
162 *
163 * @param string $localFile 本地文件的路径,缩略图的文件路径
164 * @param string $groupName 组名,最好和主文件在同一个组
165 * @param string $masterFileName 主文件名
166 * @param string $prefix 文件的前缀
167 * @param string $extName 文件的后缀,可以为空,为空时,由tracker决定
168 * @param array $meta 附件信息
169 * @param FastDFSTrackerClient $tracker
170 * @param FastDFSStorageClient $storage
171 */
172 public function storage_upload_slave_by_filename($localFile, $groupName, $masterFileName, $prefix = '', $extName = '', $meta = array(), FastDFSTrackerClient $tracker = null, FastDFSStorageClient $storage = null) {
173 $this->initTrackerAndStorage($tracker, $storage, $groupName);
174 /*echo $localFile."<br/>".$groupName."<br/>".$masterFileName."<br/>".$prefix;
175 exit;*/
176 return $this->storage->uploadSalveFile($localFile, $groupName, $masterFileName, $prefix, $extName, $meta);
177 }
178
179 /**
180 * 检查这个文件是否已经存在
181 *
182 * @param string $groupName 文件所在组名
183 * @param string $remoteFile 文件在storage中的名字
184 * @param FastDFSStorageClient $tracker
185 * @param FastDFSStorageClient $storage
186 */
187 public function storage_file_exist($groupName, $remoteFile, FastDFSTrackerClient $tracker, FastDFSStorageClient $storage) {
188 $this->initTrackerAndStorage($tracker, $storage, $groupName);
189
190 return $this->storage->fileExists($groupName, $remoteFile);
191 }
192
193 public function close() {
194 if ($this->tracker) {
195 $this->tracker->close();
196 $this->tracker = null;
197 }
198 }
199
200 public function tracker_close_all_connections() {
201 $this->close();
202 if (!$this->storage) {
203 $this->storage->close();
204 }
205 }
206
207 public static function padding($str, $len) {
208
209 $str_len = strlen($str);
210
211 return $str_len > $len ? substr($str, 0, $len) : $str . pack('x' . ($len - $str_len));
212 }
213
214 /**
215 *
216 * @param int $command
217 * @param int $length
218 * @return bytes
219 */
220 public static function packHeader($command, $length = 0) {
221 return self::packU64($length) . pack('Cx', $command);
222 }
223
224 public static function packMetaData($data) {
225 $S1 = "\x01";
226 $S2 = "\x02";
227
228 $list = array();
229 foreach ($data as $key => $val) {
230 $list[] = $key . $S2 . $val;
231 };
232
233 return implode($S1, $list);
234 }
235
236 public static function parseMetaData($data) {
237
238 $S1 = "\x01";
239 $S2 = "\x02";
240
241 $arr = explode($S1, $data);
242 $result = array();
243
244 foreach ($arr as $val) {
245 list($k, $v) = explode($S2, $val);
246 $result[$k] = $v;
247 }
248
249 return $result;
250 }
251
252 public static function parseHeader($str, $len = FDFS_HEADER_LENGTH) {
253
254 assert(strlen($str) === $len);
255
256 $result = unpack('C10', $str);
257
258 $length = self::unpackU64(substr($str, 0, 8));
259 $command = $result[9];
260 $status = $result[10];
261
262 return array(
263 'length' => $length,
264 'command' => $command,
265 'status' => $status
266 );
267 }
268
269 /**
270 * From: sphinxapi.php
271 */
272 private static function unpackU64($v) {
273 list ( $hi, $lo ) = array_values(unpack("N*N*", $v));
274
275 if (PHP_INT_SIZE >= 8) {
276 if ($hi < 0)
277 $hi += (1 << 32); // because php 5.2.2 to 5.2.5 is totally fucked up again
278 if ($lo < 0)
279 $lo += (1 << 32);
280
281 // x64, int
282 if ($hi <= 2147483647)
283 return ($hi << 32) + $lo;
284
285 // x64, bcmath
286 if (function_exists("bcmul"))
287 return bcadd($lo, bcmul($hi, "4294967296"));
288
289 // x64, no-bcmath
290 $C = 100000;
291 $h = ((int) ($hi / $C) << 32) + (int) ($lo / $C);
292 $l = (($hi % $C) << 32) + ($lo % $C);
293 if ($l > $C) {
294 $h += (int) ($l / $C);
295 $l = $l % $C;
296 }
297
298 if ($h == 0)
299 return $l;
300 return sprintf("%d%05d", $h, $l);
301 }
302
303 // x32, int
304 if ($hi == 0) {
305 if ($lo > 0)
306 return $lo;
307 return sprintf("%u", $lo);
308 }
309
310 $hi = sprintf("%u", $hi);
311 $lo = sprintf("%u", $lo);
312
313 // x32, bcmath
314 if (function_exists("bcmul"))
315 return bcadd($lo, bcmul($hi, "4294967296"));
316
317 // x32, no-bcmath
318 $hi = (float) $hi;
319 $lo = (float) $lo;
320
321 $q = floor($hi / 10000000.0);
322 $r = $hi - $q * 10000000.0;
323 $m = $lo + $r * 4967296.0;
324 $mq = floor($m / 10000000.0);
325 $l = $m - $mq * 10000000.0;
326 $h = $q * 4294967296.0 + $r * 429.0 + $mq;
327
328 $h = sprintf("%.0f", $h);
329 $l = sprintf("%07.0f", $l);
330 if ($h == "0")
331 return sprintf("%.0f", (float) $l);
332 return $h . $l;
333 }
334
335 private function initTrackerAndStorage(FastDFSTrackerClient $tracker = null, FastDFSStorageClient $storage = null, $groupName = '') {
336 $reNewStorage = false;
337 if ($tracker && $tracker !== $this->tracker) {
338 $this->tracker_get_connection();
339 }
340 if (($storage && $storage !== $this->storage) || $reNewStorage) {
341 $this->tracker_query_storage_store($groupName, $this->tracker);
342 }
343 }
344
345 /**
346 * From: sphinxapi.php
347 */
348 public static function packU64($v) {
349
350
351 assert(is_numeric($v));
352
353 // x64
354 if (PHP_INT_SIZE >= 8) {
355 assert($v >= 0);
356
357 // x64, int
358 if (is_int($v))
359 return pack("NN", $v >> 32, $v & 0xFFFFFFFF);
360
361 // x64, bcmath
362 if (function_exists("bcmul")) {
363 $h = bcdiv($v, 4294967296, 0);
364 $l = bcmod($v, 4294967296);
365 return pack("NN", $h, $l);
366 }
367
368 // x64, no-bcmath
369 $p = max(0, strlen($v) - 13);
370 $lo = (int) substr($v, $p);
371 $hi = (int) substr($v, 0, $p);
372
373 $m = $lo + $hi * 1316134912;
374 $l = $m % 4294967296;
375 $h = $hi * 2328 + (int) ($m / 4294967296);
376
377 return pack("NN", $h, $l);
378 }
379
380 // x32, int
381 if (is_int($v))
382 return pack("NN", 0, $v);
383
384 // x32, bcmath
385 if (function_exists("bcmul")) {
386 $h = bcdiv($v, "4294967296", 0);
387 $l = bcmod($v, "4294967296");
388 return pack("NN", (float) $h, (float) $l); // conversion to float is intentional; int would lose 31st bit
389 }
390
391 // x32, no-bcmath
392 $p = max(0, strlen($v) - 13);
393 $lo = (float) substr($v, $p);
394 $hi = (float) substr($v, 0, $p);
395
396 $m = $lo + $hi * 1316134912.0;
397 $q = floor($m / 4294967296.0);
398 $l = $m - ($q * 4294967296.0);
399 $h = $hi * 2328.0 + $q;
400
401 return pack("NN", $h, $l);
402 }
403
404 }
405
406 abstract class FastDFSBase {
407
408 abstract public function getSocket();
409
410 abstract public function close();
411
412 public function read($length, $socket = null) {
413 if (!$socket) {
414 $socket = $this->getSocket();
415 }
416
417 if (feof($socket)) {
418 throw new FastDFS_Exception('connection unexpectedly closed (timed out?)', $this->_errno);
419 }
420
421 $data = stream_get_contents($socket, $length);
422
423 assert($length === strlen($data));
424
425 return $data;
426 }
427
428 public function send($data, $length = 0, $socket = null) {
429 if (!$socket) {
430 $socket = $this->getSocket();
431 }
432
433 if (!$length) {
434 $length = strlen($data);
435 }
436
437 if (feof($socket) || fwrite($socket, $data, $length) !== $length) {
438 throw new Exception('connection unexpectedly closed (timed out?)');
439 }
440
441 return true;
442 }
443
444 }
445
446 class FastDFSTrackerClient extends FastDFSBase {
447
448 private $host;
449 private $port;
450
451 /**
452 *
453 * @var FastDFS
454 */
455 private $dfs;
456 private $_socket;
457
458 public function __construct(FastDFS &$dfs, $host, $port) {
459 $this->host = $host;
460 $this->port = $port;
461 $this->dfs = $dfs;
462
463 $this->_socket = @fsockopen("tcp://$host", $port, $errno, $errstr, $this->dfs->gConfig['connect_timeout']);
464 if (!$this->_socket) {
465 $this->dfs->add_error(-2, $errstr);
466 }
467 }
468
469 public function getSocket() {
470 return $this->_socket;
471 }
472
473 public function close() {
474 fclose($this->_socket);
475 }
476
477 }
478
479 class FastDFSStorageClient extends FastDFSBase {
480
481 private $groupName;
482
483 /**
484 *
485 * @var FastDFSTrackerClient
486 */
487 private $tracker;
488
489 /**
490 *
491 * @var FastDFS
492 */
493 private $dfs;
494 private $_socket;
495 private $host;
496 private $port;
497 private $storeIndex;
498
499 public function __construct(FastDFS &$dfs, $groupName, FastDFSTrackerClient $tracker) {
500 $this->tracker = $tracker;
501 $this->dfs = $dfs;
502
503 $reqBody = '';
504 if ($groupName) {
505 $cmd = FDFS_QUERY_STORE_WITH_GROUP_ONE;
506 $len = FDFS_GROUP_NAME_MAX_LEN;
507 $reqBody = FastDFS::padding($groupName, $len);
508 } else {
509 $cmd = FDFS_QUERY_STORE_WITHOUT_GROUP_ONE;
510 $len = 0;
511 }
512 $reqHeader = FastDFS::packHeader($cmd, $len);
513 $this->tracker->send($reqHeader . $reqBody);
514
515 $resHeader = $this->tracker->read(FDFS_HEADER_LENGTH);
516 $resInfo = FastDFS::parseHeader($resHeader);
517
518 if ($resInfo['status'] != 0) {
519 throw new Exception("something wrong with get storage by group name", $resInfo['status']);
520 }
521
522 $resBody = !!$resInfo['length'] ? $this->tracker->read($resInfo['length']) : '';
523 $this->groupName = trim(substr($resBody, 0, FDFS_GROUP_NAME_MAX_LEN));
524 $this->host = trim(substr($resBody, FDFS_GROUP_NAME_MAX_LEN, FDFS_IP_ADDRESS_SIZE + 1));
525
526 list(,, $this->port) = unpack('N2', substr($resBody, FDFS_GROUP_NAME_MAX_LEN + FDFS_IP_ADDRESS_SIZE - 1, FDFS_PROTO_PKG_LEN_SIZE));
527
528 $this->storeIndex = ord(substr($resBody, -1));
529
530 $this->_socket = @fsockopen($this->host, $this->port, $errno, $errstr, $this->dfs->gConfig['connect_timeout']);
531
532 if (!$this->_socket) {
533 $this->dfs->add_error($errno, $errstr);
534 }
535 }
536
537 public function getSocket() {
538 return $this->_socket;
539 }
540
541 public function getStorePathIndex() {
542 return $this->storeIndex;
543 }
544
545 public function uploadByFilename($localFile, $extName, $metas) {
546 if (!file_exists($localFile)) {
547 throw new FastDFSException("$localFile file is not exists");
548 }
549 $pathInfo = pathinfo($localFile);
550
551 $extName = $extName ? $extName : $pathInfo['extension'];
552 $extLen = strlen($extName);
553
554 if ($extLen > FDFS_FILE_EXT_NAME_MAX_LEN) {
555 throw new FastDFSException("file ext too long");
556 }
557 $fp = fopen($localFile, 'rb');
558 flock($fp, LOCK_SH);
559 $fileSize = filesize($localFile);
560
561 $reqBodyLen = 1 + FDFS_PROTO_PKG_LEN_SIZE + FDFS_FILE_EXT_NAME_MAX_LEN + $fileSize;
562 $reqHeader = FastDFS::packHeader(11, $reqBodyLen);
563 $reqBody = pack('C', $this->getStorePathIndex()) . FastDFS::packU64($fileSize) . FastDFS::padding($extName, FDFS_FILE_EXT_NAME_MAX_LEN);
564
565 $this->send($reqHeader . $reqBody);
566
567 stream_copy_to_stream($fp, $this->_socket, $fileSize);
568 flock($fp, LOCK_UN);
569 fclose($fp);
570
571 $resHeader = $this->read(FDFS_HEADER_LENGTH);
572 $resInfo = FastDFS::parseHeader($resHeader);
573
574 if ($resInfo['status'] !== 0) {
575 return false;
576 }
577 $resBody = $resInfo['length'] ? $this->read($resInfo['length']) : '';
578 $groupName = trim(substr($resBody, 0, FDFS_GROUP_NAME_MAX_LEN));
579
580 $filePath = trim(substr($resBody, FDFS_GROUP_NAME_MAX_LEN));
581
582 if ($metas) {
583 $this->setFileMetaData($groupName, $filePath, $metas);
584 }
585
586 return array(
587 'group_name' => $groupName,
588 'filename' => $filePath
589 );
590 }
591
592 /**
593 *
594 * @param type $fileName
595 * @param type $groupName
596 * @param type $masterfile
597 * @param type $prefix
598 * @param type $extName
599 * @param type $metas
600 * @return boolean
601 * @throws FastDFSException
602 */
603 public function uploadSalveFile($fileName, $groupName, $masterfile, $prefix = '', $extName = '', $metas = array()) {
604 if (!file_exists($fileName)) {
605 throw new FastDFSException("salve file $fileName is not exists");
606 }
607
608 $pathInfo = pathinfo($fileName);
609
610 $extName = $extName ? $extName : $pathInfo['extension'];
611 $extLen = strlen($extName);
612
613 if ($extLen > FDFS_FILE_EXT_NAME_MAX_LEN) {
614 throw new FastDFSException("salve file ext too long");
615 }
616 $fp = fopen($fileName, 'rb');
617 flock($fp, LOCK_SH);
618
619 $fileSize = filesize($fileName);
620 $masterFilePathLen = strlen($masterfile);
621
622 $reqBodyLength = 16 + FDFS_FILE_PREFIX_MAX_LEN + FDFS_FILE_EXT_NAME_MAX_LEN + $masterFilePathLen + $fileSize;
623 $reqHeader = FastDFS::packHeader(FDFS_PROTO_CMD_UPLOAD_SLAVE_FILE, $reqBodyLength);
624
625 $reqBody = pack('x4N', $masterFilePathLen) . FastDFS::packU64($fileSize) . FastDFS::padding($prefix, FDFS_FILE_PREFIX_MAX_LEN);
626 $reqBody .= FastDFS::padding($extName, FDFS_FILE_EXT_NAME_MAX_LEN) . $masterfile;
627
628 $this->send($reqHeader . $reqBody);
629
630 stream_copy_to_stream($fp, $this->_socket, $fileSize);
631 flock($fp, LOCK_UN);
632 fclose($fp);
633
634 $resHeader = $this->read(FDFS_HEADER_LENGTH);
635 $resInfo = FastDFS::parseHeader($resHeader);
636
637 if ($resInfo['status'] !== 0) {
638 return false;
639 }
640 $resBody = $resInfo['length'] ? $this->read($resInfo['length']) : '';
641 $groupName = trim(substr($resBody, 0, FDFS_GROUP_NAME_MAX_LEN));
642
643 $filePath = trim(substr($resBody, FDFS_GROUP_NAME_MAX_LEN));
644
645 if ($metas) {
646 $this->setFileMetaData($groupName, $filePath, $metas);
647 }
648
649 return array(
650 'group_name' => $groupName,
651 'filename' => $filePath
652 );
653 }
654
655 public function deleteFile($groupName, $fileName) {
656 $reqBodyLen = strlen($fileName) + FDFS_GROUP_NAME_MAX_LEN;
657 $reqHeader = FastDFS::packHeader(FDFS_PROTO_CMD_DELETE_FILE, $reqBodyLen);
658 $reqBody = FastDFS::padding($groupName, FDFS_GROUP_NAME_MAX_LEN) . $fileName;
659
660 $this->send($reqHeader . $reqBody);
661
662 $resHeader = $this->read(FDFS_HEADER_LENGTH);
663 $resInfo = FastDFS::parseHeader($resHeader);
664
665 return !$resInfo['status'];
666 }
667
668 public function fileExists($groupName, $filePath) {
669 $meta = $this->getFileMeta($groupName, $filePath);
670
671 return $meta ? true : false;
672 }
673
674 public function setFileMetaData($groupName, $filePath, array $metaData, $flag = FDFS_OVERWRITE_METADATA) {
675
676 $metaData = FastDFS::packMetaData($metaData);
677 $metaDataLength = strlen($metaData);
678 $filePathLength = strlen($filePath);
679 $flag = $flag === FDFS_OVERWRITE_METADATA ? 'O' : 'M';
680
681 $reqBodyLength = (FDFS_PROTO_PKG_LEN_SIZE * 2) + 1 + $metaDataLength + $filePathLength + FDFS_GROUP_NAME_MAX_LEN;
682
683 $reqHeader = FastDFS::packHeader(FDFS_PROTO_CMD_SET_METADATA, $reqBodyLength);
684
685 $reqBody = FastDFS::packU64($filePathLength) . FastDFS::packU64($metaDataLength);
686 $reqBody .= $flag . FastDFS::padding($groupName, FDFS_GROUP_NAME_MAX_LEN) . $filePath . $metaData;
687
688 $this->send($reqHeader . $reqBody);
689
690 $resHeader = $this->read(FDFS_HEADER_LENGTH);
691 $resInfo = FastDFS::parseHeader($resHeader);
692
693 return !$resInfo['status'];
694 }
695
696 /**
697 * 取得文件的元信息,如果文件不存在则,返回false,反正是一个关联数组
698 *
699 * @param type $groupName
700 * @param type $filePath
701 * @return boolean
702 */
703 public function getFileMeta($groupName, $filePath) {
704 $reqBodyLength = strlen($filePath) + FDFS_GROUP_NAME_MAX_LEN;
705 $reqHeader = FastDFS::packHeader(FDFS_PROTO_CMD_GET_METADATA, $reqBodyLength);
706 $reqBody = FastDFS::padding($groupName, FDFS_GROUP_NAME_MAX_LEN) . $filePath;
707
708 $this->send($reqHeader . $reqBody);
709
710 $resHeader = $this->read(FDFS_HEADER_LENGTH);
711 $resInfo = FastDFS::parseHeader($resHeader);
712
713 if (!!$resInfo['status']) {
714 return false;
715 }
716
717 $resBody = $resInfo['length'] ? $this->read($resInfo['length']) : false;
718
719 return FastDFS::parseMetaData($resBody);
720 }
721
722 public function close() {
723 fclose($this->_socket);
724 }
725
726 }
727
728 class FastDFSException extends Exception {
729
730 }
731
732 }
上面是api基类:
下面是调用方式:
1 /**
2 * FastDFS上传文件
3 * @param unknown $fileurl 上传文件
4 * @param unknown $sizes 附属文件
5 * @return string
6 */
7 private function applydfs($fileurl,$sizes=array()){ 9 $dfs=new FastDFS();
10 $tracker = $dfs->tracker_get_connection();
11 $location = "";
12 if($dfs->active_test($tracker)){
13 $storaged = $dfs->tracker_query_storage_store("group1",$tracker);
14 if(!empty($sizes)){
15 $count = 0;
16 $filename = $dfs->storage_upload_by_filename($fileurl);
17 if(isset($filename['group_name'])&&isset($filename['filename'])){
18 $location =$filename['group_name']."/".$filename['filename'];
19 }
20 foreach($sizes as $key=>$val){
21 $snapshot_file_info =$dfs->storage_upload_slave_by_filename($val,"group1",$filename['filename'],$key);
22 if($snapshot_file_info){
23 $count++;
24 }
25 }
26 if($count <> count($sizes)){
27 $location = "";
28 }
29 }else{
30 $filename = $dfs->storage_upload_by_filename($fileurl);
31 if(isset($filename['group_name'])&&isset($filename['filename'])){
32 $location =$filename['group_name']."/".$filename['filename'];
33 }
34 }
35 }
36 return $location;
37 }
在php.ini中配置:
1 [fastdfs]
2 ; the base path
3 fastdfs_client.base_path = /tmp
4
5 ; connect timeout in seconds
6 ; default value is 30s
7 fastdfs_client.connect_timeout = 2
8
9 ; network timeout in seconds
10 ; default value is 30s
11 fastdfs_client.network_timeout = 60
12
13 ; standard log level as syslog, case insensitive, value list:
14 ;;; emerg for emergency
15 ;;; alert
16 ;;; crit for critical
17 ;;; error
18 ;;; warn for warning
19 ;;; notice
20 ;;; info
21 ;;; debug
22 fastdfs_client.log_level = info
23
24 ; set the log filename, such as /usr/local/fastdfs/logs/fastdfs_client.log
25 ; empty for output to stderr
26 fastdfs_client.log_filename = /tmp/fastdfs_client.log
27
28 ; secret key to generate anti-steal token
29 ; this parameter must be set when http.anti_steal.check_token set to true
30 ; the length of the secret key should not exceed 128 bytes
31 fastdfs_client.http.anti_steal_secret_key =
32
33 ; FastDFS cluster count, default value is 1
34 fastdfs_client.tracker_group_count = 1
35
36 ; config file of FastDFS cluster ;, based 0
37 ; must include absolute path, such as fastdfs_client.tracker_group0
38 ; the config file is same as conf/client.conf
39 ; 这是你fastdfs的tracker的配置文件的路径,必须使用绝对路径,请换成你自己的路径,附件是我们开发环境和测试环境的client.conf配置
40 ; 测试环境已经配置过,你自己的开发环境需要配置一下
41 fastdfs_client.tracker_group0 = "E:/wamp/bin/php/php5.3.13/client.conf"
42
43 ; if use connection pool
44 ; default value is false
45 ; since V4.05
46 fastdfs_client.use_connection_pool = false
47
48 ; connections whose the idle time exceeds this time will be closed
49 ; unit: second
50 ; default value is 3600
51 ; since V4.05
52 fastdfs_client.connection_pool_max_idle_time = 3600
53
54 ; the base path
55 fastdfs_client.base_path = /tmp
56
57 ; connect timeout in seconds
58 ; default value is 30s
59 fastdfs_client.connect_timeout = 2
60
61 ; network timeout in seconds
62 ; default value is 30s
63 fastdfs_client.network_timeout = 60
|
|