CsvTool.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. namespace common\components\export;
  3. use common\enums\DownloadEnum;
  4. use common\helpers\UploadHelper;
  5. use common\models\common\Attachment;
  6. use common\models\common\Download;
  7. use common\traits\ErrorTrait;
  8. use Exception;
  9. use Yii;
  10. use yii\base\Component;
  11. class CsvTool extends Component
  12. {
  13. use ErrorTrait;
  14. const EXPORT_MODE_SYNC = 1;
  15. const EXPORT_MODE_ASYNC = 2;
  16. private $_base_dirname = 'download'; //下载中心目录
  17. private $_handler; // 文件指针
  18. public $file_dirname; //下载中心资源存放目录
  19. public $relative_filename; // 文件存储相对路径
  20. public $export_mode;
  21. public $filename;
  22. public $full_filename;
  23. public $header;
  24. public $data;
  25. public $file_size = 0;
  26. public $line_num = 0;
  27. public $download_url = '';
  28. public $absolute_dir = '';
  29. public $relative_dir = '';
  30. /**
  31. * 导出数据
  32. * @Author bing
  33. * @DateTime 2021-10-22 11:54:12
  34. * @param [type] $export_mode
  35. * @return void
  36. * @copyright: Copyright (c) 2020 广东七件事集团
  37. */
  38. public function export(bool $is_make_head = false)
  39. {
  40. try {
  41. $this->_checkParams($is_make_head);
  42. switch ($this->export_mode) {
  43. // 同步下载
  44. case self::EXPORT_MODE_SYNC:
  45. header('Content-Type: application/vnd.ms-excel');
  46. // header('Content-Disposition: attachment;filename*=utf-8' . "'zh_cn'" . iconv('utf-8', 'gbk', $this->filename . '.csv'));
  47. header("Content-Disposition: attachment;filename={$this->filename}.csv");
  48. header('Cache-Control: max-age=0');
  49. //打开PHP文件句柄,php://output 表示直接输出到浏览器
  50. $this->_handler = fopen('php://output', 'a');
  51. $this->header = $this->_handRowData($this->header);
  52. fputcsv($this->_handler, $this->header);
  53. // 数据总量
  54. if (!empty($this->data)) {
  55. $i = 0;
  56. $limit = 10000;
  57. while ($this->data[$i]) {
  58. if ($i % $limit == 0) {
  59. // 清一下缓冲区
  60. ob_flush();
  61. flush();
  62. }
  63. $row = $this->_handRowData($this->data[$i]);
  64. fputcsv($this->_handler, $row);
  65. unset($this->data[$i]);
  66. $i++;
  67. }
  68. }
  69. fclose($this->_handler);
  70. exit;
  71. break;
  72. // 异步导出至下载中心
  73. case self::EXPORT_MODE_ASYNC:
  74. $this->relative_dir = $this->_getBaseDonwLoadDir();
  75. $this->absolute_dir = Yii::getAlias('@attachment') . '/' .$this->relative_dir;
  76. $this->full_filename = $this->absolute_dir . '/' . $this->filename . '.csv';
  77. $this->relative_filename = $this->relative_dir . '/' . $this->filename . '.csv';
  78. if (!file_exists($this->full_filename)) {
  79. $this->_handler = fopen($this->full_filename, 'a+');
  80. fwrite($this->_handler, "\xEF\xBB\xBF");
  81. //将数据通过fputcsv写到文件句柄
  82. $this->header = $this->_handRowData($this->header);
  83. fputcsv($this->_handler, $this->header);
  84. }
  85. $this->_handler = fopen($this->full_filename, 'a+');
  86. $i = 0;
  87. $limit = 10000;
  88. while(!empty($this->data[$i])){
  89. if($i != 0 && $i % $limit == 0){
  90. // 清一下缓冲区
  91. ob_flush();
  92. flush();
  93. }
  94. $row = $this->_handRowData($this->data[$i]);
  95. $row = array_values($row);
  96. fputcsv($this->_handler, $row);
  97. unset($this->data[$i]);
  98. $i ++;
  99. $this->line_num ++;
  100. }
  101. fclose($this->_handler);
  102. $this->file_size = file_exists($this->full_filename) ? $this->transf_byte(filesize($this->full_filename)) : 0;
  103. break;
  104. }
  105. } catch (Exception $e) {
  106. echo $e->getMessage();
  107. $this->setError($e->getMessage());
  108. return false;
  109. }
  110. }
  111. /**
  112. * 检查参数
  113. * @Author bing
  114. * @DateTime 2021-10-22 16:04:42
  115. * @return void
  116. * @copyright: Copyright (c) 2020 广东七件事集团
  117. */
  118. private function _checkParams($is_make_head = false)
  119. {
  120. if ($is_make_head) {
  121. if (!$this->filename || !$this->header) {
  122. throw new Exception('导出参数错误');
  123. }
  124. } else {
  125. if (!$this->filename || !$this->header || !$this->data) {
  126. throw new Exception('导出参数错误');
  127. }
  128. }
  129. }
  130. /**
  131. *
  132. * @Author bing
  133. * @DateTime 2021-10-22 14:55:47
  134. * @return string //相对路径
  135. * @copyright: Copyright (c) 2020 广东七件事集团
  136. */
  137. private function _getBaseDonwLoadDir()
  138. {
  139. $relative_dir = $this->_base_dirname;
  140. $absolute_dir = Yii::getAlias('@attachment') . '/' . $this->_base_dirname;
  141. if ($this->file_dirname) {
  142. $absolute_dir .= '/' . $this->file_dirname;
  143. $relative_dir .= '/' . $this->file_dirname;
  144. }
  145. if (!is_dir($absolute_dir)) {
  146. mkdir($absolute_dir, 0777, true);
  147. }
  148. return $relative_dir;
  149. }
  150. /**
  151. * 每一列数据做处理
  152. * @Author bing
  153. * @DateTime 2021-10-22 15:59:39
  154. * @copyright: Copyright (c) 2020 广东七件事集团
  155. * @param array $row
  156. * @return array
  157. */
  158. private function _handRowData($row){
  159. return array_map(function($clo){
  160. // json不做处理
  161. try {
  162. if(is_null(json_decode($clo))){
  163. $clo = rtrim($clo, "\r\n");
  164. $clo = str_replace(",", ",", $clo);
  165. // $clo = is_string($clo) ? iconv('UTF-8', 'GBK', $clo) . "\t" : $clo;
  166. // $clo = is_string($clo) ? iconv("UTF-8", "GB2312//IGNORE", $clo) . "\t" : $clo;
  167. $clo = is_string($clo) ? $clo . "\t" : $clo;
  168. $clo = is_int($clo) ? intval($clo) : $clo;
  169. $clo = is_float($clo) ? floatval($clo) : $clo;
  170. }
  171. return $clo;
  172. } catch (\Exception $e) {
  173. return $clo;
  174. }
  175. },$row);
  176. }
  177. /**
  178. * 上传至云存储
  179. * @Author: hua
  180. * @DateTime: 2021/10/14 10:36
  181. * @Copyright: copyright (c) 2021 广东七件事集团
  182. * @param $mall_id
  183. * @param $relative_filename //相对路径的文件资源
  184. * @return string
  185. * @throws \League\Flysystem\FileExistsException
  186. * @throws \League\Flysystem\FileNotFoundException
  187. * @throws \yii\web\NotFoundHttpException
  188. */
  189. public function upload($mall_id, $relative_filename)
  190. {
  191. $config = \Yii::$app->services->attachment->getStorageConfig($mall_id);
  192. $config['mall_id'] = $mall_id;
  193. $upload = new UploadHelper($config, 'files');
  194. switch ($config['drive']) {
  195. case Attachment::DRIVE_LOCAL:
  196. return \Yii::getAlias('@attachurl') . '/'.$relative_filename;
  197. case Attachment::DRIVE_OSS:
  198. $url = $upload->upload($relative_filename);
  199. if (!empty($config['storage_aliyun_user_url'])) {
  200. return $config['storage_aliyun_transport_protocols'].'://'.$config['storage_aliyun_user_url'] . '/' . $url;
  201. }
  202. break;
  203. case Attachment::DRIVE_COS:
  204. $url = $upload->upload($relative_filename);
  205. if (!empty($config['domain'])) {
  206. return $config['domain'] . '/' . $url;
  207. }
  208. break;
  209. case Attachment::DRIVE_QINIU:
  210. $url = $upload->upload($relative_filename);
  211. if (!empty($config['domain'])) return $config['domain'] . '/' . $url;
  212. break;
  213. }
  214. }
  215. public function transf_byte($byte) {
  216. $kb = 1024;
  217. $mb = $kb * 1024;
  218. $gb = $mb * 1024;
  219. if ($byte < $kb) {
  220. return $byte . 'b';
  221. } else if ($byte < $mb) {
  222. return round($byte / $kb, 2) . 'kb';
  223. } else if ($byte < $gb) {
  224. return round($byte / $mb, 2) . 'mb';
  225. }
  226. }
  227. public function utf8ToGbk($string) {
  228. return iconv("UTF-8", "gbk//TRANSLIT", $string);
  229. }
  230. /**
  231. * @desc:上传至云存储和更新down模型
  232. * @Author: hua
  233. * @Date: 2021/11/15
  234. * @Time: 15:39
  235. * @Copyright: copyright (c) 2021 广东七件事集团
  236. * @param $download
  237. * @param $mall_id
  238. * @return mixed
  239. * @throws \League\Flysystem\FileExistsException
  240. * @throws \League\Flysystem\FileNotFoundException
  241. * @throws \yii\web\NotFoundHttpException
  242. */
  243. public function updateDown($download,$mall_id){
  244. $url = $this->upload($mall_id, $this->relative_filename);
  245. $download->status = DownloadEnum::STATUS_FINISH;
  246. $download->url = $url;
  247. $download->num = $this->line_num;
  248. $download->size = $this->file_size;
  249. return $download->save();
  250. }
  251. }