WxWorkFinanceSdk.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace weworkapi\sdk;
  3. use \FFI;
  4. class WxWorkFinanceSdk
  5. {
  6. private FFI $lib;
  7. private ?FFI\CData $sdk = null;
  8. private $options = [
  9. 'proxy_host' => "",
  10. 'proxy_password' => "",
  11. 'timeout' => 10, // 默认超时时间为10s
  12. ];
  13. /**
  14. * string $corpId 企业号
  15. * string $secret 秘钥
  16. *
  17. * 可选参数
  18. * array $options = [
  19. * 'proxy_host' => string,
  20. * 'proxy_password' => string,
  21. * 'timeout' => 10, // 默认超时时间为10s
  22. * ]
  23. */
  24. public function __construct(string $corpId, string $secret, array $options = [])
  25. {
  26. $x = FFI::new("int");
  27. var_dump($x->cdata); // int(0)
  28. die;
  29. $libDir = dirname(__DIR__) . '/sdk';
  30. $header = file_get_contents($libDir.'/WeWorkFinanceSdk_C.h');
  31. $pattern = '/^#(ifn?def) +(.*?)\n([\s\S]*?)(#endif)/m';
  32. $transformedHeader = $header;
  33. $transformedHeader = preg_replace_callback($pattern, function (array $matches): string {
  34. [, $keyword, , $body] = $matches;
  35. if ($keyword === 'ifdef') {
  36. $body = '';
  37. } elseif ($keyword === 'ifndef') {
  38. $body = '';
  39. }
  40. return $body;
  41. }, $transformedHeader);
  42. $this->lib = FFI::cdef(
  43. $transformedHeader,
  44. $libDir."/libWeWorkFinanceSdk_C.so"
  45. );
  46. $this->sdk = $this->lib->NewSdk();
  47. $ret = $this->lib->Init($this->sdk, $corpId, $secret);
  48. if ($ret != 0) {
  49. // sdk需要主动释放
  50. $this->lib->DestroySdk($this->sdk);
  51. $this->sdk = null;
  52. $msg = sprintf("init sdk err ret: %d\n", $ret);
  53. throw new WxworkFinanceSdkException($msg);
  54. }
  55. $this->options = array_merge($this->options, $options);
  56. }
  57. public function __destruct()
  58. {
  59. // sdk需要主动释放
  60. if(!is_null($this->sdk)) {
  61. $this->lib->DestroySdk($this->sdk);
  62. }
  63. }
  64. public function getChatData(int $seq = 0, int $limit = 10): string
  65. {
  66. $chatDatas = $this->lib->NewSlice();
  67. $ret = $this->lib->GetChatData($this->sdk, $seq, $limit,
  68. $this->options['proxy_host'],
  69. $this->options['proxy_password'],
  70. $this->options['timeout'],
  71. $chatDatas);
  72. if ($ret != 0) {
  73. $this->lib->FreeSlice($chatDatas);
  74. $msg = sprintf("GetChatData err ret:%d\n", $ret);
  75. throw new WxworkFinanceSdkException($msg);
  76. }
  77. // printf("GetChatData len:%d data:%s\n", $chatDatas->len, FFI::string($chatDatas->buf));
  78. $data = FFI::string($this->lib->GetContentFromSlice($chatDatas), $this->lib->GetSliceLen($chatDatas));
  79. $this->lib->FreeSlice($chatDatas);
  80. return $data;
  81. }
  82. /**
  83. * 下载资源
  84. * $sdkfileid 资源ID,来自chat中的数据sdkfileid
  85. * $saveTo 本地保存的路径
  86. */
  87. public function downloadMedia(string $sdkfileid, string $saveTo): bool
  88. {
  89. $mediaDatas = $this->lib->NewMediaData();
  90. $fp = fopen($saveTo, "wb");
  91. do {
  92. $ret = $this->lib->GetMediaData($this->sdk, $this->lib->GetOutIndexBuf($mediaDatas),
  93. $sdkfileid,
  94. $this->options['proxy_host'],
  95. $this->options['proxy_password'],
  96. $this->options['timeout'],
  97. $mediaDatas
  98. );
  99. if (0 != $ret) {
  100. $this->lib->FreeMediaData($mediaDatas);
  101. fclose($fp) && unlink($saveTo);
  102. $msg = sprintf("sdk sdk media data err, ret: %d\n", $ret);
  103. throw new WxworkFinanceSdkException($msg);
  104. }
  105. // FILE_APPEND
  106. $data = FFI::string($this->lib->GetData($mediaDatas), $this->lib->GetDataLen($mediaDatas));
  107. fwrite($fp, $data, $this->lib->GetDataLen($mediaDatas));
  108. } while($this->lib->IsMediaDataFinish($mediaDatas) == 0);
  109. fclose($fp);
  110. $this->lib->FreeMediaData($mediaDatas);
  111. return true;
  112. }
  113. /**
  114. * 拉取静态资源数据,用于可以支持追加模式的三方存储平台
  115. *
  116. * 返回的数据结构体
  117. * $ret = [
  118. * 'data' => '' // string 返回的数据
  119. * 'nextIndex' => 'ddd' // string 获取下一段数据的句柄
  120. * 'isFinished' => int // 1 数据已拉取完毕
  121. * ];
  122. */
  123. public function getMediaData(string $sdkfileid, string $indexBuf = ""): array
  124. {
  125. $mediaDatas = $this->lib->NewMediaData();
  126. $ret = $this->lib->GetMediaData($this->sdk, $indexBuf, $sdkfileid,
  127. $this->options['proxy_host'],
  128. $this->options['proxy_password'],
  129. $this->options['timeout'],
  130. $mediaDatas
  131. );
  132. if (0 != $ret) {
  133. $this->lib->FreeMediaData($mediaDatas);
  134. $msg = sprintf("sdk sdk media data err, ret: %d\n", $ret);
  135. throw new WxworkFinanceSdkException($msg);
  136. }
  137. $data = FFI::string($this->lib->GetData($mediaDatas), $this->lib->GetDataLen($mediaDatas));
  138. $nextIndex = $this->lib->GetOutIndexBuf($mediaDatas);
  139. $isFinished = $this->lib->IsMediaDataFinish($mediaDatas) == 1 ?: 0;
  140. $this->lib->FreeMediaData($mediaDatas);
  141. return [
  142. "data" => $data,
  143. "nextIndex" => FFI::string($nextIndex),
  144. "isFinished" => $isFinished,
  145. ];
  146. }
  147. /**
  148. * 解密数据
  149. * $randomKey 通过openssl解密后的key
  150. * $encryptStr chats 的加密数据
  151. */
  152. public function decryptData(string $randomKey, string $encryptStr): string
  153. {
  154. $chatDatas = $this->lib->NewSlice();
  155. $ret = $this->lib->DecryptData($randomKey, $encryptStr, $chatDatas);
  156. $data = FFI::string($this->lib->GetContentFromSlice($chatDatas), $this->lib->GetSliceLen($chatDatas));
  157. $this->lib->FreeSlice($chatDatas);
  158. return $data;
  159. }
  160. }