SellerTaobaoImport.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. <?php
  2. namespace app\home\controller;
  3. use think\facade\View;
  4. use think\facade\Lang;
  5. use think\facade\Db;
  6. /**
  7. * ============================================================================
  8. * DSMall多用户商城
  9. * ============================================================================
  10. * 版权所有 2014-2028 长沙德尚网络科技有限公司,并保留所有权利。
  11. * 网站地址: http://www.csdeshang.com
  12. * ----------------------------------------------------------------------------
  13. * 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用 .
  14. * 不允许对程序代码以任何形式任何目的的再发布。
  15. * ============================================================================
  16. * 控制器
  17. */
  18. class SellerTaobaoImport extends BaseSeller {
  19. public function initialize() {
  20. parent::initialize();
  21. error_reporting(E_ERROR | E_WARNING);
  22. Lang::load(base_path() . 'home/lang/' . config('lang.default_lang') . '/sellergoodsadd.lang.php');
  23. }
  24. public function index() {
  25. if (!request()->isPost()) {
  26. /**
  27. * 获取商品分类
  28. */
  29. $gc = model('goodsclass');
  30. $gc_list = $gc->getGoodsClass(session('store_id'));
  31. View::assign('gc_list', $gc_list);
  32. /**
  33. * 获取店铺商品分类
  34. */
  35. $model_store_class = model('storegoodsclass');
  36. $store_goods_class = $model_store_class->getClassTree(array('store_id' => session('store_id'), 'storegc_state' => '1'));
  37. View::assign('store_goods_class', $store_goods_class);
  38. if (input('get.step') != '') {
  39. View::assign('step', input('get.step'));
  40. } else {
  41. View::assign('step', '1');
  42. }
  43. } else {
  44. $file = $_FILES['csv'];
  45. /**
  46. * 上传文件存在判断
  47. */
  48. if (empty($file['name'])) {
  49. $this->error(lang('store_goods_import_choose_file'));
  50. }
  51. /**
  52. * 文件来源判定
  53. */
  54. if (!is_uploaded_file($file['tmp_name'])) {
  55. $this->error(lang('store_goods_import_unknown_file'));
  56. }
  57. /**
  58. * 文件类型判定
  59. */
  60. $file_name_array = explode('.', $file['name']);
  61. if ($file_name_array[count($file_name_array) - 1] != 'csv') {
  62. $this->error(lang('store_goods_import_wrong_type') . $file_name_array[count($file_name_array) - 1]);
  63. }
  64. /**
  65. * 文件大小判定
  66. */
  67. if ($file['size'] > intval(ini_get('upload_max_filesize')) * 1024 * 1024) {
  68. $this->error(lang('store_goods_import_size_limit'));
  69. }
  70. /**
  71. * 商品分类判定
  72. */
  73. if (empty(input('post.gc_id'))) {
  74. $this->error(lang('store_goods_import_wrong_class'));
  75. }
  76. $gc = model('goodsclass');
  77. $gc_row = $gc->getGoodsClassLineForTag(input('post.gc_id'));
  78. if (!is_array($gc_row) or count($gc_row) == 0) {
  79. $this->error(lang('store_goods_import_wrong_class1'));
  80. }
  81. $gc_sub_list = $gc->getGoodsClassList(array('gc_parent_id' => intval(input('post.gc_id'))));
  82. if (is_array($gc_sub_list) and count($gc_sub_list) > 0) {
  83. $this->error(lang('store_goods_import_wrong_class2'));
  84. }
  85. /**
  86. * 店铺商品分类判定
  87. */
  88. $sgcate_ids = array();
  89. $stc = model('storegoodsclass');
  90. if (is_array(input('post.sgcate_id/a')) and count(input('post.sgcate_id/a')) > 0) {
  91. foreach (input('post.sgcate_id/a') as $sgcate_id) {
  92. if (!in_array($sgcate_id, $sgcate_ids)) {
  93. $stc_row = $stc->getStoregoodsclassInfo(array('storegc_id' => $sgcate_id));
  94. if (is_array($stc_row) and count($stc_row) > 0) {
  95. $sgcate_ids[] = $sgcate_id;
  96. }
  97. }
  98. }
  99. }
  100. /**
  101. * 上传文件的字符编码转换
  102. */
  103. $csv_string = $this->unicodeToUtf8(file_get_contents($file['tmp_name']));
  104. /* 兼容淘宝助理5 start */
  105. $csv_array = explode("\tsyncStatus", $csv_string, 2);
  106. if (count($csv_array) == 2) {
  107. $csv_string = $csv_array[1];
  108. }
  109. /* 兼容淘宝助理5 end */
  110. /**
  111. * 将文件转换为二维数组形式的商品数据
  112. */
  113. $records = $this->parse_taobao_csv($csv_string);
  114. if ($records === false) {
  115. $this->error(lang('store_goods_import_wrong_column'));
  116. }
  117. /**
  118. * 转码
  119. */
  120. if (strtoupper(CHARSET) == 'GBK') {
  121. $records = $this->getGBK($records);
  122. }
  123. $model_goodsclass = model('goodsclass');
  124. $model_store_goods = model('goods');
  125. // 商品数量
  126. $goods_num = $model_store_goods->getGoodsCommonCount(array('store_id' => session('store_id')));
  127. /**
  128. * 商品数,空间使用,使用期限判断
  129. */
  130. $model_store = model('store');
  131. $store_info = $model_store->getStoreInfo(array('store_id' => session('store_id')));
  132. $model_store_grade = model('storegrade');
  133. $store_grade = $model_store_grade->getOneStoregrade($store_info['grade_id']);
  134. /* 商品数判断 */
  135. $remain_num = -1;
  136. if (intval($store_grade['sg_goods_limit']) != 0) {
  137. if ($goods_num >= $store_grade['sg_goods_limit']) {
  138. $this->error(lang('store_goods_index_goods_limit') . $store_grade['sg_goods_limit'] . lang('store_goods_index_goods_limit1'));
  139. }
  140. $remain_num = $store_grade['sg_goods_limit'] - $goods_num;
  141. }
  142. /* 使用期限判断 */
  143. if (intval($store_info['store_end_time']) != 0) {
  144. if (TIMESTAMP >= $store_info['store_end_time']) {
  145. $this->error(lang('store_goods_index_time_limit'));
  146. }
  147. }
  148. /**
  149. * 循环添加数据
  150. */
  151. $str = '';
  152. if (is_array($records) and count($records) > 0) {
  153. foreach ($records as $k => $record) {
  154. if ($remain_num > 0 and $k >= $remain_num) {
  155. $this->error(lang('store_goods_index_goods_limit') . $store_grade['sg_goods_limit'] . lang('store_goods_index_goods_limit1') . lang('store_goods_import_end') . (count($records) - $remain_num) . lang('store_goods_import_products_no_import'), (string)url('SellerTaobaoImport/index', ['step' => 4]));
  156. }
  157. if (is_array($record['goods_image'])) {
  158. $str .= implode(',', $record['goods_image']);
  159. $str .= "\r\n";
  160. } else {
  161. $str .= $record['goods_image'] . "\r\n";
  162. }
  163. //file_put_contents('image.txt',$str,FILE_APPEND);
  164. $pic_array = $this->get_goods_image($record['goods_image']);
  165. if (empty($record['goods_name']))
  166. continue;
  167. $param = array();
  168. $param['goods_name'] = $record['goods_name'];
  169. $param['gc_id'] = intval(input('post.gc_id'));
  170. $param['gc_id_1'] = intval(input('post.cls_1'));
  171. $param['gc_id_2'] = intval(input('post.cls_2'));
  172. $param['gc_id_3'] = intval(input('post.cls_3'));
  173. $param['gc_name'] = input('post.cate_name');
  174. $param['spec_name'] = 'N;';
  175. $param['spec_value'] = 'N;';
  176. $param['store_name'] = $store_info['store_name'];
  177. $param['store_id'] = session('store_id');
  178. $param['type_id'] = '0';
  179. $param['goods_image'] = $pic_array['goods_image'][0];
  180. $param['goods_marketprice'] = $record['goods_store_price'];
  181. $param['goods_costprice'] = $record['goods_store_price'];
  182. $param['goods_discount'] = 1;
  183. $param['goods_price'] = $record['goods_store_price'];
  184. //$param['goods_show'] = '1';
  185. $param['goods_commend'] = $record['goods_commend'];
  186. $param['goods_addtime'] = TIMESTAMP;
  187. $param['goods_shelftime'] = TIMESTAMP;//上架时间
  188. $param['goods_attr'] = '';
  189. $param['goods_body'] = $record['goods_body'];
  190. $param['goods_state'] = '0';
  191. $param['goods_verify'] = '1';
  192. $param['areaid_1'] = intval(input('post.province_id'));
  193. $param['areaid_2'] = intval(input('post.city_id'));
  194. $param['goods_stcids'] = ',' . implode(',', array_unique(input('post.sgcate_id/a'))) . ',';
  195. $param['goods_serial'] = $record['goods_serial'];
  196. $goods_id = $model_store_goods->addGoodsCommon($param);
  197. //添加库存
  198. $param = array();
  199. $param['goods_commonid'] = $goods_id;
  200. $param['goods_name'] = $record['goods_name'];
  201. $param['gc_id'] = intval(input('post.gc_id'));
  202. $param['store_id'] = session('store_id');
  203. $param['goods_image'] = $pic_array['goods_image'][0];
  204. $param['goods_marketprice'] = $record['goods_store_price'];
  205. $param['goods_price'] = $record['goods_store_price'];
  206. //$param['goods_show'] = '1';
  207. $param['goods_commend'] = $record['goods_commend'];
  208. $param['goods_addtime'] = TIMESTAMP;
  209. $param['goods_edittime'] = TIMESTAMP;
  210. $param['goods_state'] = '0';
  211. $param['goods_verify'] = '1';
  212. $param['areaid_1'] = intval(input('post.province_id'));
  213. $param['areaid_2'] = intval(input('post.city_id'));
  214. $param['goods_stcids'] = ',' . implode(',', array_unique(input('post.sgcate_id/a'))) . ',';
  215. $param['goods_storage'] = $record['spec_goods_storage'];
  216. $param['goods_serial'] = $record['goods_serial'];
  217. $param['gc_id_1'] = intval(input('post.cls_1'));
  218. $param['gc_id_2'] = intval(input('post.cls_2'));
  219. $param['gc_id_3'] = intval(input('post.cls_3'));
  220. $param['goods_promotion_price'] = $param['goods_price'];
  221. $param['goods_spec'] = 'N;';
  222. $param['store_name'] = $store_info['store_name'];
  223. $goods_id1 = $model_store_goods->addGoods($param);
  224. //规格导入
  225. // 更新常用分类信息
  226. $goods_class = $model_goodsclass->getGoodsClassLineForTag(input('post.gc_id'));
  227. $goods_id_str .= "," . $goods_id;
  228. if ($goods_id) {
  229. /**
  230. * 添加商品的店铺分类表
  231. */
  232. /**
  233. * 商品多图的添加
  234. */
  235. if (!empty($pic_array['goods_image']) && is_array($pic_array['goods_image'])) {
  236. $insert_array = array();
  237. foreach ($pic_array['goods_image'] as $pic) {
  238. if ($pic == '')
  239. continue;
  240. $param = array();
  241. $param['goodsimage_url'] = $pic;
  242. $param['store_id'] = session('store_id');
  243. $param['goods_commonid'] = $goods_id;
  244. $insert_array[] = $param;
  245. }
  246. //$rs = model('upload');
  247. //$rs = $rs->add($param);
  248. $rs = $model_store_goods->addGoodsImagesAll($insert_array);
  249. }
  250. }
  251. }
  252. if ($goods_id_str != "") {
  253. View::assign('goods_id_str', substr($goods_id_str, 1, strlen($goods_id_str)));
  254. }
  255. }
  256. View::assign('step', '4');
  257. }
  258. /**
  259. * 相册分类
  260. */
  261. $model_album = model('album');
  262. $param = array();
  263. $param['store_id'] = session('store_id');
  264. $aclass_info = $model_album->getAlbumclassList($param);
  265. View::assign('aclass_info', $aclass_info);
  266. /* 设置卖家当前菜单 */
  267. $this->setSellerCurMenu('seller_taobao_import');
  268. $this->setSellerCurItem();
  269. return View::fetch($this->template_dir . 'index');
  270. }
  271. public function import_image() {
  272. View::assign('session_id', $this->app->session->getId());
  273. return View::fetch($this->template_dir . 'import_image');
  274. }
  275. public function upload() {
  276. $time=TIMESTAMP;
  277. if (isset($_FILES["Filedata"]) || !is_uploaded_file($_FILES["Filedata"]["tmp_name"]) || $_FILES["Filedata"]["error"] != 0) {
  278. $store_id = session('store_id');
  279. $path = BASE_UPLOAD_PATH . DIRECTORY_SEPARATOR . ATTACH_GOODS . DIRECTORY_SEPARATOR . $store_id . DIRECTORY_SEPARATOR . date('Ymd',$time); //取得上传图片的绝对路径
  280. $SID = $store_id . "_";
  281. if (!is_dir($path)) {
  282. mkdir($path, 0777,true);
  283. }//如果目录不存在,则创建
  284. $path = realpath($path) . '/';
  285. $filetype = '.jpg'; //后缀
  286. $upload_file = $_FILES['Filedata']; //上传的数据
  287. $file_info = pathinfo($upload_file['name']); //图片数组
  288. $sourimgname = $file_info['filename']; //不带后缀文件名,入库
  289. $save_name = date('YmdHis',$time) . rand(10000, 99999);
  290. $rukuimgname = $SID . $save_name . $filetype; //带后缀入库的名字
  291. $save = $path . $rukuimgname; //将要保存到服务器的路径
  292. $name = $_FILES['Filedata']['tmp_name']; //上传到服务器的临时文件
  293. //echo $save;
  294. if (!move_uploaded_file($name, $save)) {
  295. exit;
  296. }
  297. //生成不同规格大小的图片
  298. $fz60 = $path . $SID . $save_name . '_60.jpg';
  299. $fz240 = $path . $SID . $save_name . '_240.jpg';
  300. $fz360 = $path . $SID . $save_name . '_360.jpg';
  301. $fz1280 = $path . $SID . $save_name . '_1280.jpg';
  302. if (copy($save, $fz60)) {
  303. //更改图片大小
  304. $this->resizeimage($fz60, 60, 60, $fz60);
  305. }
  306. if (copy($save, $fz240)) {
  307. //更改图片大小
  308. $this->resizeimage($fz240, 240, 240, $fz240);
  309. }
  310. if (copy($save, $fz360)) {
  311. //更改图片大小
  312. $this->resizeimage($fz360, 360, 360, $fz360);
  313. }
  314. if (copy($save, $fz1280)) {
  315. //更改图片大小
  316. $this->resizeimage($fz1280, 1280, 1280, $fz1280);
  317. }
  318. Db::startTrans();
  319. try {
  320. //更新goods表
  321. $result = model('goods')->editGoods(array('goods_image' => $rukuimgname), array('goods_image' => $sourimgname));
  322. if (!$result) {
  323. // throw new \think\Exception('更新goods表失败', 10006);
  324. }
  325. //更新goodscommon表
  326. $temp=Db::name('goodscommon')->where(array(array('store_id','=',$this->store_info['store_id']),array('goods_body','like','%'.$sourimgname.'%')))->order('goods_commonid desc')->find();
  327. if($temp){
  328. $temp['goods_body']=preg_replace('/"([^"]+)'.$sourimgname.'([^"]+)"/i','"'.UPLOAD_SITE_URL."/home/store/goods/".session('store_id')."/".date('Ymd',$time)."/".$rukuimgname.'"',$temp['goods_body']);
  329. model('goods')->editGoodsCommon(array('goods_body' => $temp['goods_body']), array('goods_commonid' => $temp['goods_commonid']));
  330. }
  331. $result = model('goods')->editGoodsCommon(array('goods_image' => $rukuimgname), array('goods_image' => $sourimgname));
  332. if (!$result) {
  333. // throw new \think\Exception('更新goodscommon表失败', 10006);
  334. }
  335. //更新goodsimages表
  336. $result = model('goods')->editGoodsImages(array('goodsimage_url' => $rukuimgname), array('goodsimage_url' => $sourimgname));
  337. if (!$result) {
  338. // throw new \think\Exception('更新goodsimages表失败', 10006);
  339. }
  340. //插入albumpic表
  341. $insert_array = array();
  342. $insert_array['apic_name'] = $rukuimgname;
  343. $insert_array['apic_tag'] = '';
  344. $insert_array['aclass_id'] = 1;
  345. $insert_array['apic_cover'] = $rukuimgname;
  346. $insert_array['apic_size'] = '';
  347. $insert_array['apic_spec'] = '';
  348. $insert_array['apic_uploadtime'] = $time;
  349. $insert_array['store_id'] = $store_id;
  350. $result = model('album')->addAlbumpic($insert_array);
  351. if (!$result) {
  352. // throw new \think\Exception('插入albumpic表失败', 10006);
  353. }
  354. } catch (\Exception $e) {
  355. Db::rollback();
  356. throw new \think\Exception($e->getMessage(), 10006);
  357. }
  358. Db::commit();
  359. }
  360. }
  361. /*
  362. * 图片缩略图
  363. */
  364. private function resizeimage($srcfile, $ratew = '', $rateh = '', $filename = "") {
  365. $size = getimagesize($srcfile);
  366. switch ($size[2]) {
  367. case 1:
  368. $img = imagecreatefromgif($srcfile);
  369. break;
  370. case 2:
  371. $img = imagecreatefromjpeg($srcfile); //从源文件建立一个新图片
  372. break;
  373. case 3:
  374. $img = imagecreatefrompng($srcfile);
  375. break;
  376. default:
  377. exit;
  378. }
  379. //源图片的宽度和高度
  380. $srcw = imagesx($img);
  381. echo '源文件的宽度' . $srcw . '<br />';
  382. $srch = imagesy($img);
  383. echo '源文件的高度' . $srch . '<br />';
  384. //目的图片的宽度和高度
  385. $dstw = $ratew;
  386. $dsth = $rateh;
  387. //新建一个真彩色图像
  388. echo '新图片的宽度' . $dstw . '高度' . $dsth . '<br />';
  389. $im = imagecreatetruecolor($dstw, $dsth);
  390. $black = imagecolorallocate($im, 255, 255, 255);
  391. imagefilledrectangle($im, 0, 0, $dstw, $dsth, $black);
  392. imagecopyresized($im, $img, 0, 0, 0, 0, $dstw, $dsth, $srcw, $srch);
  393. // 以 JPEG 格式将图像输出到浏览器或文件
  394. if ($filename) {
  395. //图片保存输出
  396. imagejpeg($im, $filename, 100);
  397. }
  398. //释放图片
  399. imagedestroy($im);
  400. imagedestroy($img);
  401. }
  402. /**
  403. * 得到数组变量的GBK编码
  404. *
  405. * @param array $key 数组
  406. * @return array 数组类型的返回结果
  407. */
  408. private function getGBK($key) {
  409. /**
  410. * 转码
  411. */
  412. if (strtoupper(CHARSET) == 'GBK' && !empty($key)) {
  413. if (is_array($key)) {
  414. $result = var_export($key, true); //变为字符串
  415. $result = iconv('UTF-8', 'GBK', $result);
  416. eval("\$result = $result;"); //转换回数组
  417. } else {
  418. $result = iconv('UTF-8', 'GBK', $key);
  419. }
  420. }
  421. return $result;
  422. }
  423. /**
  424. * unicode转为utf8
  425. * @param string $str 待转的字符串
  426. * @return string
  427. */
  428. function unicodeToUtf8($str, $order = "little") {
  429. $utf8string = "";
  430. $n = strlen($str);
  431. for ($i = 0; $i < $n; $i++) {
  432. if ($order == "little") {
  433. $val = str_pad(dechex(ord($str[$i + 1])), 2, 0, STR_PAD_LEFT) .
  434. str_pad(dechex(ord($str[$i])), 2, 0, STR_PAD_LEFT);
  435. } else {
  436. $val = str_pad(dechex(ord($str[$i])), 2, 0, STR_PAD_LEFT) .
  437. str_pad(dechex(ord($str[$i + 1])), 2, 0, STR_PAD_LEFT);
  438. }
  439. $val = intval($val, 16); // 由于上次的.连接,导致$val变为字符串,这里得转回来。
  440. $i++; // 两个字节表示一个unicode字符。
  441. $c = "";
  442. if ($val < 0x7F) { // 0000-007F
  443. $c .= chr($val);
  444. } elseif ($val < 0x800) { // 0080-07F0
  445. $c .= chr(0xC0 | ($val / 64));
  446. $c .= chr(0x80 | ($val % 64));
  447. } else { // 0800-FFFF
  448. $c .= chr(0xE0 | (($val / 64) / 64));
  449. $c .= chr(0x80 | (($val / 64) % 64));
  450. $c .= chr(0x80 | ($val % 64));
  451. }
  452. $utf8string .= $c;
  453. }
  454. /* 去除bom标记 才能使内置的iconv函数正确转换 */
  455. if (ord(substr($utf8string, 0, 1)) == 0xEF && ord(substr($utf8string, 1, 2)) == 0xBB && ord(substr($utf8string, 2, 1)) == 0xBF) {
  456. $utf8string = substr($utf8string, 3);
  457. }
  458. return $utf8string;
  459. }
  460. private function get_goods_image($pic_string) {
  461. if ($pic_string == '') {
  462. return false;
  463. }
  464. $pic_array = explode(';', $pic_string);
  465. if (!empty($pic_array) && is_array($pic_array)) {
  466. $array = array();
  467. $goods_image = array();
  468. $multi_image = array();
  469. $i = 0;
  470. foreach ($pic_array as $v) {
  471. if ($v != '') {
  472. $line = explode(':', $v); //[0] 文件名tbi [2] 排序
  473. $goods_image[] = $line[0];
  474. }
  475. }
  476. $array['goods_image'] = array_unique($goods_image);
  477. $str = implode(',', $array['goods_image']) . "\r\n";
  478. file_put_contents('imgarr.txt', $str, FILE_APPEND);
  479. return $array;
  480. } else {
  481. return false;
  482. }
  483. }
  484. /**
  485. * 淘宝数据字段名
  486. *
  487. * @return array
  488. */
  489. private function taobao_fields() {
  490. return array(
  491. 'goods_name' => '宝贝名称',
  492. 'cid' => '宝贝类目',
  493. 'goods_form' => '新旧程度',
  494. 'goods_store_price' => '宝贝价格',
  495. 'spec_goods_storage' => '宝贝数量',
  496. 'goods_indate' => '有效期',
  497. 'goods_transfee_charge' => '运费承担',
  498. 'py_price' => '平邮',
  499. 'es_price' => 'EMS',
  500. 'kd_price' => '快递',
  501. //'goods_show' => '放入仓库',
  502. 'spec' => '销售属性别名',
  503. 'goods_commend' => '橱窗推荐',
  504. 'goods_body' => '宝贝描述',
  505. 'goods_image' => '新图片',
  506. 'goods_serial' => '商家编码'
  507. );
  508. }
  509. /**
  510. * 每个字段所在CSV中的列序号,从0开始算
  511. *
  512. * @param array $title_arr
  513. * @param array $import_fields
  514. * @return array
  515. */
  516. private function taobao_fields_cols($title_arr, $import_fields) {
  517. $fields_cols = array();
  518. foreach ($import_fields as $k => $field) {
  519. $pos = array_search($field, $title_arr);
  520. if ($pos !== false) {
  521. $fields_cols[$k] = $pos;
  522. }
  523. }
  524. return $fields_cols;
  525. }
  526. /**
  527. * 解析淘宝助理CSV数据
  528. *
  529. * @param string $csv_string
  530. * @return string
  531. */
  532. private function parse_taobao_csv($csv_string) {
  533. //防止乱码
  534. $scount = strpos($csv_string, "宝贝名称");
  535. $csv_string = substr($csv_string, $scount);
  536. /* 定义CSV文件中几个标识性的字符的ascii码值 */
  537. define('ORD_SPACE', 32); // 空格
  538. define('ORD_QUOTE', 34); // 双引号
  539. define('ORD_TAB', 9); // 制表符
  540. define('ORD_N', 10); // 换行\n
  541. define('ORD_R', 13); // 换行\r
  542. /* 字段信息 */
  543. $import_fields = $this->taobao_fields(); // 需要导入的字段在CSV中显示的名称
  544. $fields_cols = array(); // 每个字段所在CSV中的列序号,从0开始算
  545. $csv_col_num = 0; // csv文件总列数
  546. $pos = 0; // 当前的字符偏移量
  547. $status = 0; // 0标题未开始 1标题已开始
  548. $title_pos = 0; // 标题开始位置
  549. $records = array(); // 记录集
  550. $field = 0; // 字段号
  551. $start_pos = 0; // 字段开始位置
  552. $field_status = 0; // 0未开始 1双引号字段开始 2无双引号字段开始
  553. $line = 0; // 数据行号
  554. while ($pos < strlen($csv_string)) {
  555. $t = ord($csv_string[$pos]); // 每个UTF-8字符第一个字节单元的ascii码
  556. $next = ord($csv_string[$pos + 1]);
  557. $next2 = ord($csv_string[$pos + 2]);
  558. $next3 = ord($csv_string[$pos + 3]);
  559. if ($status == 0 && !in_array($t, array(ORD_SPACE, ORD_TAB, ORD_N, ORD_R))) {
  560. $status = 1;
  561. $title_pos = $pos;
  562. }
  563. if ($status == 1) {
  564. if ($field_status == 0 && $t == ORD_N) {
  565. static $flag = null;
  566. if ($flag === null) {
  567. $title_str = substr($csv_string, $title_pos, $pos - $title_pos);
  568. $title_arr = explode("\t", trim($title_str));
  569. $fields_cols = $this->taobao_fields_cols($title_arr, $import_fields);
  570. if (count($fields_cols) != count($import_fields)) {
  571. return false;
  572. }
  573. $csv_col_num = count($title_arr); // csv总列数
  574. $flag = 1;
  575. }
  576. if ($next == ORD_QUOTE) {
  577. $field_status = 1; // 引号数据单元开始
  578. $start_pos = $pos = $pos + 2; // 数据单元开始位置(相对\n偏移+2)
  579. } else {
  580. $field_status = 2; // 无引号数据单元开始
  581. $start_pos = $pos = $pos + 1; // 数据单元开始位置(相对\n偏移+1)
  582. }
  583. continue;
  584. }
  585. if ($field_status == 1 && $t == ORD_QUOTE && in_array($next, array(ORD_N, ORD_R, ORD_TAB))) { // 引号+换行 或 引号+\t
  586. $records[$line][$field] = addslashes(substr($csv_string, $start_pos, $pos - $start_pos));
  587. $field++;
  588. if ($field == $csv_col_num) {
  589. $line++;
  590. $field = 0;
  591. $field_status = 0;
  592. continue;
  593. }
  594. if (($next == ORD_N && $next2 == ORD_QUOTE) || ($next == ORD_TAB && $next2 == ORD_QUOTE) || ($next == ORD_R && $next2 == ORD_QUOTE)) {
  595. $field_status = 1;
  596. $start_pos = $pos = $pos + 3;
  597. continue;
  598. }
  599. if (($next == ORD_N && $next2 != ORD_QUOTE) || ($next == ORD_TAB && $next2 != ORD_QUOTE) || ($next == ORD_R && $next2 != ORD_QUOTE)) {
  600. $field_status = 2;
  601. $start_pos = $pos = $pos + 2;
  602. continue;
  603. }
  604. if ($next == ORD_R && $next2 == ORD_N && $next3 == ORD_QUOTE) {
  605. $field_status = 1;
  606. $start_pos = $pos = $pos + 4;
  607. continue;
  608. }
  609. if ($next == ORD_R && $next2 == ORD_N && $next3 != ORD_QUOTE) {
  610. $field_status = 2;
  611. $start_pos = $pos = $pos + 3;
  612. continue;
  613. }
  614. }
  615. if ($field_status == 2 && in_array($t, array(ORD_N, ORD_R, ORD_TAB))) { // 换行 或 \t
  616. $records[$line][$field] = addslashes(substr($csv_string, $start_pos, $pos - $start_pos));
  617. $field++;
  618. if ($field == $csv_col_num) {
  619. $line++;
  620. $field = 0;
  621. $field_status = 0;
  622. continue;
  623. }
  624. if (($t == ORD_N && $next == ORD_QUOTE) || ($t == ORD_TAB && $next == ORD_QUOTE) || ($t == ORD_R && $next == ORD_QUOTE)) {
  625. $field_status = 1;
  626. $start_pos = $pos = $pos + 2;
  627. continue;
  628. }
  629. if (($t == ORD_N && $next != ORD_QUOTE) || ($t == ORD_TAB && $next != ORD_QUOTE) || ($t == ORD_R && $next != ORD_QUOTE)) {
  630. $field_status = 2;
  631. $start_pos = $pos = $pos + 1;
  632. continue;
  633. }
  634. if ($t == ORD_R && $next == ORD_N && $next2 == ORD_QUOTE) {
  635. $field_status = 1;
  636. $start_pos = $pos = $pos + 3;
  637. continue;
  638. }
  639. if ($t == ORD_R && $next == ORD_N && $next2 != ORD_QUOTE) {
  640. $field_status = 2;
  641. $start_pos = $pos = $pos + 2;
  642. continue;
  643. }
  644. }
  645. }
  646. if ($t > 0 && $t <= 127) {
  647. $pos++;
  648. } elseif (192 <= $t && $t <= 223) {
  649. $pos += 2;
  650. } elseif (224 <= $t && $t <= 239) {
  651. $pos += 3;
  652. } elseif (240 <= $t && $t <= 247) {
  653. $pos += 4;
  654. } elseif (248 <= $t && $t <= 251) {
  655. $pos += 5;
  656. } elseif ($t == 252 || $t == 253) {
  657. $pos += 6;
  658. } else {
  659. $pos++;
  660. }
  661. }
  662. $return = array();
  663. foreach ($records as $key => $record) {
  664. foreach ($record as $k => $col) {
  665. $col = trim($col); // 去掉数据两端的空格
  666. /* 对字段数据进行分别处理 */
  667. switch ($k) {
  668. case $fields_cols['goods_body'] : $return[$key]['goods_body'] = str_replace('\"\"', '"', $col);
  669. break;
  670. case $fields_cols['goods_image'] : $return[$key]['goods_image'] = trim($col, '"');
  671. break;
  672. //case $fields_cols['goods_show'] : $return[$key]['goods_show'] = $col == 1 ? 0 : 1; break;
  673. case $fields_cols['goods_name'] : $return[$key]['goods_name'] = $col;
  674. break;
  675. case $fields_cols['spec_goods_storage'] : $return[$key]['spec_goods_storage'] = $col;
  676. break;
  677. case $fields_cols['goods_store_price']: $return[$key]['goods_store_price'] = $col;
  678. break;
  679. case $fields_cols['goods_commend'] : $return[$key]['goods_commend'] = $col;
  680. break;
  681. case $fields_cols['spec'] : $return[$key]['spec'] = $col;
  682. break;
  683. case $fields_cols['sale_attr'] : $return[$key]['sale_attr'] = $col;
  684. break;
  685. case $fields_cols['goods_form'] : $return[$key]['goods_form'] = $col;
  686. break;
  687. case $fields_cols['goods_transfee_charge'] : $return[$key]['goods_transfee_charge'] = $col;
  688. break;
  689. case $fields_cols['py_price'] : $return[$key]['py_price'] = $col;
  690. break;
  691. case $fields_cols['es_price'] : $return[$key]['es_price'] = $col;
  692. break;
  693. case $fields_cols['kd_price'] : $return[$key]['kd_price'] = $col;
  694. break;
  695. case $fields_cols['goods_serial'] : $return[$key]['goods_serial'] = $col;
  696. break;
  697. // case $fields_cols['goods_indate'] : $return[$key]['goods_indate'] = $col; break;
  698. }
  699. }
  700. }
  701. return $return;
  702. }
  703. }