resumable_io.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. require_once("http.php");
  3. require_once("auth_digest.php");
  4. // ----------------------------------------------------------
  5. // class Qiniu_Rio_PutExtra
  6. class Qiniu_Rio_PutExtra
  7. {
  8. public $Bucket = null; // 必选(未来会没有这个字段)。
  9. public $Params = null;
  10. public $MimeType = null;
  11. public $ChunkSize = 0; // 可选。每次上传的Chunk大小
  12. public $TryTimes = 3; // 可选。尝试次数
  13. public $Progresses = null; // 可选。上传进度:[]BlkputRet
  14. public $Notify = null; // 进度通知:func(blkIdx int, blkSize int, ret *BlkputRet)
  15. public $NotifyErr = null; // 错误通知:func(blkIdx int, blkSize int, err error)
  16. public function __construct($bucket = null) {
  17. $this->Bucket = $bucket;
  18. }
  19. }
  20. // ----------------------------------------------------------
  21. // func Qiniu_Rio_BlockCount
  22. define('QINIU_RIO_BLOCK_BITS', 22);
  23. define('QINIU_RIO_BLOCK_SIZE', 1 << QINIU_RIO_BLOCK_BITS); // 4M
  24. function Qiniu_Rio_BlockCount($fsize) // => $blockCnt
  25. {
  26. return ($fsize + (QINIU_RIO_BLOCK_SIZE - 1)) >> QINIU_RIO_BLOCK_BITS;
  27. }
  28. // ----------------------------------------------------------
  29. // internal func Qiniu_Rio_Mkblock/Mkfile
  30. function Qiniu_Rio_Mkblock($self, $host, $reader, $size) // => ($blkputRet, $err)
  31. {
  32. if (is_resource($reader)) {
  33. $body = fread($reader, $size);
  34. if ($body === false) {
  35. $err = new Qiniu_Error(0, 'fread failed');
  36. return array(null, $err);
  37. }
  38. } else {
  39. list($body, $err) = $reader->Read($size);
  40. if ($err !== null) {
  41. return array(null, $err);
  42. }
  43. }
  44. if (strlen($body) != $size) {
  45. $err = new Qiniu_Error(0, 'fread failed: unexpected eof');
  46. return array(null, $err);
  47. }
  48. $url = $host . '/mkblk/' . $size;
  49. return Qiniu_Client_CallWithForm($self, $url, $body, 'application/octet-stream');
  50. }
  51. function Qiniu_Rio_Mkfile($self, $host, $key, $fsize, $extra) // => ($putRet, $err)
  52. {
  53. $url = $host . '/mkfile/' . $fsize;
  54. if ($key !== null) {
  55. $url .= '/key/' . Qiniu_Encode($key);
  56. }
  57. if (!empty($extra->MimeType)) {
  58. $url .= '/mimeType/' . Qiniu_Encode($extra->MimeType);
  59. }
  60. if (!empty($extra->Params)) {
  61. foreach ($extra->Params as $k=>$v) {
  62. $url .= "/" . $k . "/" . Qiniu_Encode($v);
  63. }
  64. }
  65. $ctxs = array();
  66. foreach ($extra->Progresses as $prog) {
  67. $ctxs []= $prog['ctx'];
  68. }
  69. $body = implode(',', $ctxs);
  70. return Qiniu_Client_CallWithForm($self, $url, $body, 'application/octet-stream');
  71. }
  72. // ----------------------------------------------------------
  73. // class Qiniu_Rio_UploadClient
  74. class Qiniu_Rio_UploadClient
  75. {
  76. public $uptoken;
  77. public function __construct($uptoken)
  78. {
  79. $this->uptoken = $uptoken;
  80. }
  81. public function RoundTrip($req) // => ($resp, $error)
  82. {
  83. $token = $this->uptoken;
  84. $req->Header['Authorization'] = "UpToken $token";
  85. return Qiniu_Client_do($req);
  86. }
  87. }
  88. // ----------------------------------------------------------
  89. // class Qiniu_Rio_Put/PutFile
  90. function Qiniu_Rio_Put($upToken, $key, $body, $fsize, $putExtra) // => ($putRet, $err)
  91. {
  92. global $QINIU_UP_HOST;
  93. $self = new Qiniu_Rio_UploadClient($upToken);
  94. $progresses = array();
  95. $uploaded = 0;
  96. while ($uploaded < $fsize) {
  97. $tried = 0;
  98. $tryTimes = ($putExtra->TryTimes > 0) ? $putExtra->TryTimes : 1;
  99. $blkputRet = null;
  100. $err = null;
  101. if ($fsize < $uploaded + QINIU_RIO_BLOCK_SIZE) {
  102. $bsize = $fsize - $uploaded;
  103. } else {
  104. $bsize = QINIU_RIO_BLOCK_SIZE;
  105. }
  106. while ($tried < $tryTimes) {
  107. list($blkputRet, $err) = Qiniu_Rio_Mkblock($self, $QINIU_UP_HOST, $body, $bsize);
  108. if ($err === null) {
  109. break;
  110. }
  111. $tried += 1;
  112. continue;
  113. }
  114. if ($err !== null) {
  115. return array(null, $err);
  116. }
  117. if ($blkputRet === null ) {
  118. $err = new Qiniu_Error(0, "rio: uploaded without ret");
  119. return array(null, $err);
  120. }
  121. $uploaded += $bsize;
  122. $progresses []= $blkputRet;
  123. }
  124. $putExtra->Progresses = $progresses;
  125. return Qiniu_Rio_Mkfile($self, $QINIU_UP_HOST, $key, $fsize, $putExtra);
  126. }
  127. function Qiniu_Rio_PutFile($upToken, $key, $localFile, $putExtra) // => ($putRet, $err)
  128. {
  129. $fp = fopen($localFile, 'rb');
  130. if ($fp === false) {
  131. $err = new Qiniu_Error(0, 'fopen failed');
  132. return array(null, $err);
  133. }
  134. $fi = fstat($fp);
  135. $result = Qiniu_Rio_Put($upToken, $key, $fp, $fi['size'], $putExtra);
  136. fclose($fp);
  137. return $result;
  138. }
  139. // ----------------------------------------------------------