c = new Client(); // 建構 model 調用器 $this->eventManagementDb = new Event(); $this->itemManagementDb = new Item(); $this->submitManagementDb = new Submit(); $this->syslogManagementDb = new Syslog(); $this->syslogactManagementDb = new Syslogact(); $this->syslogtManagementDb = new Syslogt(); $this->playerManagementDb = new Player(); $this->roundManagementDb = new Round(); $this->goodManagementDb = new Good(); $this->sessionManagementDb = new Session(); $this->checkinManagementDb = new CheckinGpAlloc(); $this->gameManagementDb = new GameGpRatio(); $this->activityManagementDb = new Activity(); $this->receiptManagementDb = new Receipt(); $this->tplayerManagementDb = new TPlayer(); $this->troundManagementDb = new TRound(); $this->tsessionManagementDb = new TSession(); $this->tgoodManagementDb = new TGood(); $this->tcheckinManagementDb = new TCheckinGpAlloc(); $this->authLineUsersDb = new AuthLineUsers(); $this->settingManagementSv = new SettingManagementService(); $this->settingManagementSv = new SettingManagementService(); $this->basedir = preg_replace('/\/app\/.*/', '/public/', __DIR__); $this->imgC = new ImageAnnotatorClient([ 'credentials' => $this->basedir . 'private/google.json', ]); } // 申報系統(已廢棄) public function hashParse($hash) { $hash = \DB::select("SELECT FROM_BASE64(AES_DECRYPT(UNHEX(\"" . $hash . "\"), \"" . env('KK') . "\")) as str;"); return explode(',', $hash[0]->str); } public function hashCheck($hash) { // 格式判斷 if (count($hash) != 2) return false; // 業務邏輯判斷 $items = $this->eventManagementDb ->leftJoin('items', 'events.id', '=', 'items.eid') ->select([ 'events.archive', ]) ->where('events.id', $hash[0]) ->where('items.id', $hash[1]) ->where('events.date_begin', '<=', date("Y-m-d")) ->where('events.date_final', '>=', date("Y-m-d")) ->get() ->toArray(); if (count($items) == 0) return false; return ($items[0]['archive'] == GeneralConst::ARCHIVE_NO) ? true : false; } public function getinfo($hash) { // 業務邏輯判斷 $info = $this->eventManagementDb ->leftJoin('items', 'events.id', '=', 'items.eid') ->select([ 'events.name', 'events.kv', 'events.email', 'events.tel', \DB::raw("items.name as item_name"), 'items.is_ide', 'items.id_acc', ]) ->where('events.id', $hash[0]) ->where('items.id', $hash[1]) ->where('events.date_begin', '<=', date("Y-m-d")) ->where('events.date_final', '>=', date("Y-m-d")) ->first() ->toArray(); return $info; } public function makePDF($info, $name, $identity, $add_host, $add_contact, $tel, $ida, $idb, $acc) { // 初期設定 $options = new Options(); $options->set('isRemoteEnabled', true); $options->set('chroot', '/'); $dompdf = new Dompdf(); $dompdf->setOptions($options); // 內容拼湊 $html = '' . '申報資料
' . '姓名: ' . $name . '
' . '身分證字號: ' . $identity . '
' . '戶籍地址: ' . $add_host . '
' . '通訊地址: ' . $add_contact . '
' . '電話: ' . $tel . '
' . '
' . '檢附文件:
' . '[is_ide]' . '[id_acc]' . ''; if ($info['is_ide'] == GeneralConst::PHOTO_YES) { $html = str_replace('[is_ide]', '
身分證正面
' . '
' . '
身分證背面
' . '
' , $html); } else { $html = str_replace('[is_ide]', '', $html); } if ($info['id_acc'] == GeneralConst::PHOTO_YES) { $html = str_replace('[id_acc]', '
存摺
' . '
' , $html); } else { $html = str_replace('[id_acc]', '', $html); } $dompdf->setPaper('A4'); $dompdf->loadHtml($html, 'UTF-8'); $dompdf->render(); $output = $dompdf->output(); // 路徑命名 $dirname = 'material'; $date = date("Ymd"); if (!file_exists($dirname)) mkdir($dirname, 0777, true); if (!file_exists($dirname . '/' . GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['web_path'])) mkdir($dirname . '/' . GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['web_path'], 0777, true); if (!file_exists($dirname . '/' . GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['web_path'] . '/' . $date)) mkdir($dirname . '/' . GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['web_path'] . '/' . $date, 0777, true); $basepath = $dirname . '/' . GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['web_path'] . '/' . $date . '/'; $time = md5(bcrypt(microtime())); file_put_contents($basepath . $time . GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['ext'], $output); return $basepath . $time . GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['ext']; } public function savedata($iid, $name, $identity, $add_host, $add_contact, $tel, $ida, $idb, $acc, $pdf) { // 取得參數 // 調用資料庫(或者其他業務邏輯) $this->submitManagementDb ->insert([ 'iid' => $iid, 'name' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $name . "'), \"" . env('KK') . "\"))"), 'identity' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $identity . "'), \"" . env('KK') . "\"))"), 'add_host' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $add_host . "'), \"" . env('KK') . "\"))"), 'add_contact' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $add_contact . "'), \"" . env('KK') . "\"))"), 'tel' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $tel . "'), \"" . env('KK') . "\"))"), GeneralConst::$appendixMap[ GeneralConst::APPENDIX_IDENTITY_FRONT ]['sql'] => $ida, GeneralConst::$appendixMap[ GeneralConst::APPENDIX_IDENTITY_BACK ]['sql'] => $idb, GeneralConst::$appendixMap[ GeneralConst::APPENDIX_PASSBOOK ]['sql'] => $acc, GeneralConst::$appendixMap[ GeneralConst::APPENDIX_DECLARE_PDF ]['sql'] => $pdf, 'cdate' => date('Y-m-d H:i:s'), ]); $id = \DB::getPdo()->lastInsertId(); // 整理返回值並返回 return $id; } // 小遊戲 // LINE 好友判斷 (實作介接直通部分) public function lineFriendCheck($lineId, $from = null) { try { // 本次調用的參數整理 $uid = $lineId; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'UID' => $uid, ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'UID' => $uid, ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ], 'timeout' => 15, // Response timeout 'connect_timeout' => 10, // Connection timeout // 'on_stats' => function (\GuzzleHttp\TransferStats $stats) use ($rqid) { // if ($stats->hasResponse()) { // $this->debuglog('lineFriendCheck-on_stats_ok', [ // 'rqid' => $rqid ?? 0 // ], [ // 'transferTime' => $stats->getTransferTime(), // 'handlerStats' => $stats->getHandlerStats(), // ]); // } else { // $this->debuglog('lineFriendCheck-on_stats_ng', [ // 'rqid' => $rqid ?? 0 // ], [ // 'handlerErrorData' => $stats->getHandlerErrorData(), // ]); // } // } ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $requestTime = date("Y-m-d H:i:s"); $logdata['requestTime'] = $requestTime; $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/contact/QueryQualification', $req); $res = $response->getBody(); // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'QueryQualification', 'k' => $uid, 'cdate' => date("Y-m-d H:i:s"), ]; if ($from) $data['kk'] = $from; // 區分來源(紀錄的 log 表不同) $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = $res; $this->syslog($data); // 返回值判斷 $res = json_decode($res); $rcode = $res->RCode ?? ''; if ($rcode != '0000') return false; $isfollow = $res->Result->IsFollow ?? false; $ismember = $res->Result->IsTWPMember ?? false; if (!$isfollow || !$ismember) return false; } catch (Exception $ex) { // 錯誤可能發生在 memoIn 或是 out // $data['memoIn'] = json_encode(['error' => 'exception', 'param' => array_merge($param, $logdata)], JSON_UNESCAPED_UNICODE); // $data['memoOut'] = json_encode(['code' => $ex->getCode(), 'msg' => $ex->getMessage()], JSON_UNESCAPED_UNICODE); // $this->syslog($data); $this->debuglog('lineFriendCheck', [ 'rqid' => $rqid ?? 0 ], [ 'errCode' => $ex->getCode(), 'requestTime' => $requestTime ?? '', 'logTime' => date("Y-m-d H:i:s"), 'errMsg' => $ex->getMessage(), ]); return false; } return true; } public function isAuthUserExists($lineUserId) { return $this->authLineUsersDb->where('lineUserId', $lineUserId)->exists(); } public function addAuthUser($lineUserId) { $this->authLineUsersDb->insert([ 'lineUserId' => $lineUserId ]); } // LINE 取得個資(建立在好友判斷後才可以執行) public function lineProfile($lineId) { $response = $this->c->request('GET', env('LINE_API_BASE') . 'bot/profile/' . $lineId, [ 'headers' => [ 'Content-Type' => 'application/json; charset=utf-8', 'Accept' => '*/*', 'Authorization' => 'Bearer ' . env('LINE_CHANNEL_TOKEN'), 'Accept-Encoding' => 'gzip, deflate, br', ] ]); $profile = json_decode($response->getBody()); return $profile; } // 新增或取得用戶資訊 public function playerinfo($lineId) { // 取得用戶在本地的資訊 $playerinfo = $this->playerManagementDb ->select(['id']) ->where('lineId', $lineId) ->get() ->toArray(); // 取得用戶在 LINE 上的 profile // $profile = $this->lineProfile($lineId); if (count($playerinfo) == 0) { // 用戶不在本地資料庫,新增 // 寫入資料表 $d = [ 'lineId' => $lineId, 'userName' => '', 'userPhoto' => '', 'gp' => 0, 'cdate' => date("Y-m-d H:i:s"), 'mdate' => date("Y-m-d H:i:s"), ]; $this->playerManagementDb ->insert($d); $id = \DB::getPdo()->lastInsertId(); // 替用互打一次性標籤 $this->playerTag($lineId); } else { // 用戶的 LINE 資訊可能會更新,所以這個 API 還身兼更新資訊的功能 // $d = [ // 'userName' => $profile->displayName, // 'userPhoto' => $profile->pictureUrl, // ]; // $this->playerManagementDb // ->where('lineId', $lineId) // ->update($d); } // 再重新查一遍 $playerinfo = $this->playerManagementDb ->select([ // 'id', 'lineId', // 'userName', // 'userPhoto', 'gp', // 'cdate', // 'mdate', ]) ->where('lineId', $lineId) ->first() ->toArray(); return $playerinfo; } // 檢查是否在本地有資料 public function isPlayer($lineId) { $playerinfo = $this->playerManagementDb->select(['id'])->where('lineId', $lineId)->get()->toArray(); return (count($playerinfo) > 0); } // 取得回合資訊 public function roundinfo($lineId) { // 回合資訊 $roundinfo = $this->roundManagementDb ->select(['id', 'dateBegin', 'dateFinal']) ->where('dateFinal', '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get(); if (count($roundinfo) == 0) { return false; } else { $roundinfo = $roundinfo->toArray(); } // 簽到資訊 $checkininfo = $this->sessionManagementDb ->select(['eventDate', 'currentGameGp']) ->where('lineId', $lineId) ->where('rid', $roundinfo[0]['id']) ->where('gid', '<>', 0) // 僅篩選簽到或遊戲 ->orderby('id', 'asc') // 確保按照時間排 ->get() ->toArray(); // 整理 $res = [ 'dateBegin' => $roundinfo[0]['dateBegin'], 'dateFinal' => $roundinfo[0]['dateFinal'], 'today' => date("Y-m-d"), 'checkins' => [], ]; foreach ($checkininfo as $c) { // 相同天可能會有重新再玩,因此會有超過1筆資料的可能,不想使用 SQL group by 耗能 $res['checkins'][ $c['eventDate'] ] = [ 'date' => $c['eventDate'], 'canplay' => ($c['eventDate'] != date("Y-m-d")) ? false : ($c['currentGameGp'] < 0) ? true : false, ]; } $res['checkins'] = array_values($res['checkins']); return $res; } // 取得獎項兌換資訊 public function goodinfo($lineId) { // 獎項資訊 $goodinfo = $this->goodManagementDb ->select(['id', 'lp', 'gp', 'active', 'totalQty', 'issuedQty']) ->get() ->toArray(); // 一定有獎項所以不防呆 // 回合資訊 (注意用於兌獎資訊的日期區間判定與玩遊戲不同) $roundinfo = $this->roundManagementDb ->select(['id']) ->where(\DB::raw("DATE_ADD(dateFinal, INTERVAL +redeemExtra DAY)"), '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get(); // 若由 INFO 調用,則會先調用回合資訊確保來到這邊時一定拿到數值 // 若由 REDEEM 調用,由於回合的日期限制比兌換的日期限制來的窄,不能優先於函數執行 // 因此這邊有可能拿不到值,需要防呆 if (count($roundinfo) == 0) { return false; } else { $roundinfo = $roundinfo->toArray(); } // player 準備資料 $playerinfo = $this->playerManagementDb->select(['gp'])->where('lineId', $lineId)->get(); if (count($playerinfo) == 0) { return false; } else { $playerinfo = $playerinfo->toArray(); } $mygp = $playerinfo[0]['gp']; // 兌獎資訊 $redeeminfo = $this->sessionManagementDb ->select(['cid']) // 獎項 ID ->where('lineId', $lineId) ->where('rid', $roundinfo[0]['id']) ->where('cid', '<>', 0) // 僅篩選兌獎 ->get() ->toArray(); $redeemIds = []; foreach ($redeeminfo as $r) $redeemIds[] = $r['cid']; // 整理 $res = []; foreach ($goodinfo as $g) { // 稽核用,如果已核發數量 >= 可發數量,就不顯示 if ($g['issuedQty'] >= $g['totalQty'] && $g['totalQty'] > 0) { continue; } // 可用性限制 $issoldout = false; $isredeemed = false; $isnomoney = false; $canuse = false; if ($g['totalQty'] - $g['issuedQty'] <= $this->settingManagementSv->getSetting()['GAME_ISSUE_BUFFER']) $issoldout = true; if (in_array($g['id'], $redeemIds)) $isredeemed = true; if ($mygp < $g['gp']) $isnomoney = true; if ( ($g['totalQty'] - $g['issuedQty'] > $this->settingManagementSv->getSetting()['GAME_ISSUE_BUFFER']) // 核發數量限制還夠 && (!in_array($g['id'], $redeemIds)) // 本回合沒有兌換過 && ($mygp >= $g['gp']) // 自己的吉點足夠 ) { $canuse = true; } // 最後一道防線就是新添加的 active 欄位(一般來說如果其他三個偵測有任何一個是 true 的話,canuse 就是 false ;但是當其他三個偵測都是 false 的情況如果 canuse 也是 false 就是該獎項被關閉) if ($g['active'] == GeneralConst::ACTIVE_NO) $canuse = false; $res[] = [ 'id' => $g['id'], 'lp' => $g['lp'], // 獎項名 'gp' => $g['gp'], // 所需吉點 'issoldout' => $issoldout, // 是否全數兌換完畢 'isredeemed' => $isredeemed, // 是否已兌換過 'isnomoney' => $isnomoney, // 是否吉點還夠 'canuse' => $canuse, // 綜合顯示 ]; } return $res; } // 是否今日可玩遊戲 public function canPlay($lineId) { // 回合資訊 $roundinfo = $this->roundManagementDb ->select(['id']) ->where('dateFinal', '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get(); if (count($roundinfo) == 0) { return false; } else { $roundinfo = $roundinfo->toArray(); } $playinfo = $this->sessionManagementDb ->select(['currentGameGp']) ->where('lineId', $lineId) ->where('rid', $roundinfo[0]['id']) ->where('gid', '<>', 0) // 僅篩選簽到或遊戲 ->where('eventDate', date("Y-m-d")) ->get() ->toArray(); // 可用性限制 $canplay = true; foreach ($playinfo as $p) { // 目前只有在玩一次的狀態是 -1 if ($p['currentGameGp'] >= 0) $canplay = false; } return $canplay; } // 玩遊戲簽到(建立在可玩的狀態下才會進來) public function playGameAndCheckin($lineId, $name) { // 回合資訊 $roundinfo = $this->roundManagementDb ->select(['id']) ->where('dateFinal', '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get() ->toArray(); // 一定有回合所以不防呆(參考本函數註解) // 依照比例決定返回的轉盤結果 $gameinfo = $this->gameManagementDb ->select(['id', 'ratio', 'gp']) ->get() ->toArray(); $gameArr = []; foreach ($gameinfo as $g) for ($i = 0; $i < $g['ratio']; $i++) $gameArr[] = ['id' => $g['id'], 'gp' => $g['gp']]; shuffle($gameArr); // 依照簽到狀態決定需不需要簽到 & 決定簽到吉點 $playinfo = $this->sessionManagementDb ->select(['currentCheckinGp', 'eventDate']) ->where('lineId', $lineId) ->where('rid', $roundinfo[0]['id']) ->where('gid', '<>', 0) // 僅篩選簽到或遊戲 ->get() ->toArray(); $cancheckin = true; $checkins = 0; // 本回合不含這一次,共簽到過幾次 foreach ($playinfo as $p) { // 檢驗當天是否有簽到 if ($p['eventDate'] == date("Y-m-d")) { // 目前只有在玩一次的狀態是 -1 if ($p['currentCheckinGp'] >= 0) $cancheckin = false; } // 統計本回合已簽到過幾次 if ($p['currentCheckinGp'] > 0) { $checkins++; } } if ($lineId == $this->settingManagementSv->getSetting()['GAME_TESTING_LINE_ID']) $checkins = 0; $currentCheckinGp = ($cancheckin) ? $this->getGpByCheckins($checkins + 1) : 0; // 拼湊 session 紀錄 $currentGp = ((($gameArr[0]['gp'] < 0) ? 0 : $gameArr[0]['gp']) + ($currentCheckinGp)); // 將遊戲吉點小於 0 的部分歸零 $res = [ 'pid' => $this->getPidBylineId($lineId), 'lineId' => $lineId, 'userName' => $name, 'rid' => $roundinfo[0]['id'], 'gid' => $gameArr[0]['id'], 'cid' => 0, 'eventDate' => date("Y-m-d"), 'currentGp' => $currentGp, 'currentGameGp' => $gameArr[0]['gp'], 'currentCheckinGp' => $currentCheckinGp, 'cdate' => date('Y-m-d H:i:s'), ]; $this->sessionManagementDb->insert($res); $id = \DB::getPdo()->lastInsertId(); $res['id'] = $id; // 上檔玩家吉點計算 $res['gp'] = $this->addGpToPlayer($lineId, $currentGp); return $res; } public function getPidBylineId($lineId) { $info = $this->playerManagementDb->select(['id'])->where('lineId', $lineId)->first()->toArray(); return $info['id']; } public function getGpByCheckins($checkins) { $info = $this->checkinManagementDb->select(['gp'])->where('day', $checkins)->first()->toArray(); return $info['gp']; } public function addGpToPlayer($lineId, $gp) { $info = $this->playerManagementDb->select(['gp'])->where('lineId', $lineId)->first()->toArray(); $gp += $info['gp']; $this->playerManagementDb->where('lineId', $lineId)->update(['gp' => $gp]); return $gp; } // 兌點(建立在 goodinfo 執行過確認兌獎資格的情況) // 採取策略是我們資料庫先改動 > 調用直通 > 如果直通有問題我們就會加註 MEMO > 但本地的資料就不更改了,避免重複讓用戶調用 public function redeemGood($lineId, $gid, $name) { $redeeminfo = []; try { // 回合資訊 (注意用於兌獎資訊的日期區間判定與玩遊戲不同) $roundinfo = $this->roundManagementDb ->select(['id']) ->where(\DB::raw("DATE_ADD(dateFinal, INTERVAL +redeemExtra DAY)"), '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get() ->toArray(); // 來到這邊代表一定有資料 // good 準備資料 $goodinfo = $this->goodManagementDb->select(['issuedQty', 'gp', 'lp'])->where('id', $gid)->first()->toArray(); $fromIssuedQty = $goodinfo['issuedQty']; $toIssuedQty = $fromIssuedQty + 1; // player 準備資料 $playerinfo = $this->playerManagementDb->select(['gp'])->where('lineId', $lineId)->first()->toArray(); $fromGp = $playerinfo['gp']; $toGp = $playerinfo['gp'] - $goodinfo['gp']; // 直通打點與確認 (先打點,依照返回正確與否再決定要不要後續操作本地資料) if ($this->settingManagementSv->getSetting()['GAME_ESI_LINEPOINT'] == 'true') { // 共用變數 $uid = $lineId; $rqidA = $this->getRqId(); $rqidB = $this->getRqId(); $seedKey = $this->getSeedKey(); $divDataA = $this->getDivData(); $divDataB = $this->getDivData(); // // // 1/2 打點 // // // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divDataA); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'UID' => $uid, 'Amount' => $goodinfo['lp'], ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'ICV' => $icv, 'DivData' => $divDataA, 'MAC' => $mac, 'UID' => $uid, 'Amount' => $goodinfo['lp'], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'LinepointIssue', 'k' => $uid, 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/linepoint/issue', $req); $resA = json_decode($response->getBody()); $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode($resA, JSON_UNESCAPED_UNICODE); $this->syslog($data); // // // 2/2 打點確認 // // // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divDataB); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidB, 'QueryRqid' => $rqidA, // 剛才的RQID 'UID' => $uid, ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidB, 'ICV' => $icv, 'DivData' => $divDataB, 'MAC' => $mac, 'QueryRqid' => $rqidA, // 剛才的RQID 'UID' => $uid, ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'LinepointQuery', 'k' => $uid, 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/linepoint/query', $req); $resB = json_decode($response->getBody()); $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode($resB, JSON_UNESCAPED_UNICODE); $this->syslog($data); // 打點返回成功,需要確認 // 確認成功,對用戶返回已打點的資訊,也計入資料庫 // 確認失敗,對用戶返回已打點的資訊,也計入資料庫(差別只在於 LOG 註記的內容不同) // 打點返回失敗,需要確認 // 確認成功,對用戶返回已打點的資訊,也計入資料庫(差別也只在於 LOG 註記的內容不同) // 確認失敗,報錯 if ($resA->RCode != '0000' && $resB->RCode != '0000') { return false; } } // session 插入 $res = [ 'pid' => $this->getPidBylineId($lineId), 'lineId' => $lineId, 'userName' => $name, 'rid' => $roundinfo[0]['id'], 'gid' => 0, // 注意這是轉盤的獎項 ID 不是兌獎的 ID 'cid' => $gid, 'eventDate' => date("Y-m-d"), 'currentGp' => -$goodinfo['gp'], 'currentGameGp' => 0, 'currentCheckinGp' => 0, 'cdate' => date('Y-m-d H:i:s'), ]; $this->sessionManagementDb->insert($res); // good 更新資料 $this->goodManagementDb->where('id', $gid)->update(['issuedQty' => $toIssuedQty]); // player 更新資料 $this->playerManagementDb->where('lineId', $lineId)->update(['gp' => $toGp]); // 整理本地紀錄資料 $redeeminfo = [ 'player' => [ 'lineId' => $lineId, 'fromGp' => $fromGp, 'toGp' => $toGp, ], 'good' => [ 'id' => $gid, 'fromIssuedQty' => $fromIssuedQty, 'toIssuedQty' => $toIssuedQty, ], 'session' => $res, ]; } catch (Exception $ex) { // 錯誤可能發生在 memoIn 或是 out $data['memoIn'] = json_encode(['error' => 'exception'], JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode(['code' => $ex->getCode(), 'msg' => $ex->getMessage()], JSON_UNESCAPED_UNICODE); $this->syslog($data); return false; } return $redeeminfo; } public function playerTag($lineId) { try { // 本次調用的參數整理 $tid = $this->settingManagementSv->getSetting()['GAME_CURRENT_TAG']; $uid = $lineId; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'TagTagging', 'k' => $uid, 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ], 'timeout' => 15, // Response timeout 'connect_timeout' => 10, // Connection timeout 'on_stats' => function (\GuzzleHttp\TransferStats $stats) use ($rqid) { if ($stats->hasResponse()) { $this->debuglog('playerTag-on_stats_ok', [ 'rqid' => $rqid ?? 0 ], [ 'transferTime' => $stats->getTransferTime(), 'handlerStats' => $stats->getHandlerStats(), ]); } else { $this->debuglog('playerTag-on_stats_ng', [ 'rqid' => $rqid ?? 0 ], [ 'handlerErrorData' => $stats->getHandlerErrorData(), ]); } } ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $requestTime = date("Y-m-d H:i:s"); $logdata['requestTime'] = $requestTime; $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/tag/Tagging', $req); $res = $response->getBody(); // 經由計算取得的完整 request JSON $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); // 調用 API 取得返回 $data['memoOut'] = $res; // 紀錄 $this->syslog($data); } catch (Exception $ex) { // 錯誤可能發生在 memoIn 或是 out // $data['memoIn'] = json_encode(['error' => 'exception'], JSON_UNESCAPED_UNICODE); // $data['memoOut'] = json_encode(['code' => $ex->getCode(), 'msg' => $ex->getMessage()], JSON_UNESCAPED_UNICODE); // $this->syslog($data); $this->debuglog('playerTag', [ 'rqid' => $rqid ?? 0 ], [ 'errCode' => $ex->getCode(), 'requestTime' => $requestTime ?? '', 'logTime' => date("Y-m-d H:i:s"), 'errMsg' => $ex->getMessage(), ]); return false; } return true; } public function syslog($sysLog) { // 此功能暫時只有小遊戲+類發票有,所以偵測 k 值存在才紀錄 if (isset($sysLog['k'])) { if (!isset($sysLog['kk'])) { // 偵測到不存在特殊 kk 鍵的請求就進入小遊戲 $this->syslogManagementDb->insert($sysLog); } else { // 偵測到存在特殊 kk 鍵的請求就 if ($sysLog['kk'] == 'activity') { //進入類發票(需要先移除特殊鍵) unset($sysLog['kk']); $this->syslogactManagementDb->insert($sysLog); } if ($sysLog['kk'] == 'tmz') { //進入串門子(需要先移除特殊鍵) unset($sysLog['kk']); $this->syslogtManagementDb->insert($sysLog); } } } return true; } public function debuglog($func, $dataIn, $dataOut = '') { $this->syslogManagementDb->insert([ 'type' => 'debug', 'func' => $func, 'k' => $_SERVER['SERVER_ADDR'], 'memoIn' => json_encode($dataIn), 'memoOut' => substr(json_encode($dataOut),0,1024), 'cdate' => date("Y-m-d H:i:s"), ]); } // 直通 API 串聯流程 public function esiFlow() { // 本次調用的參數整理 $tid = '87B3984D-15EC-480C-8E23-25275F2D2DF2'; $uid = 'Ud2534d6e1eed9cee2c919a993443352b'; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 調用 try { $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/tag/Tagging', $req); $res = $response->getBody(); } catch (Exception $ex) { } // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'TagTagging', 'k' => '', 'cdate' => date("Y-m-d H:i:s"), ]; // 經由計算取得的完整 request JSON $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); // 調用 API 取得返回 $data['memoOut'] = $res; // 紀錄 $this->syslog($data); return $res; } public function esiFlowTagUpdate() { // 本次調用的參數整理 $tid = 'f7d27d19-b05e-4ec8-bb49-2c5b0525e095'; $uid = 'Ud2534d6e1eed9cee2c919a993443352b'; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'Tags' => [ [ 'Tagid' => $tid, 'Name' => '奧美測試用標籤' . date("YmdHis"), ] ], ]); //$msgRaw = preg_replace('/[\-]/', '', $msgRaw); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'Tags' => [ [ 'Tagid' => $tid, 'Name' => '奧美測試用標籤' . date("YmdHis"), ] ], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/tag/Update', $req); $res = $response->getBody(); // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'TagUpdate', 'k' => '', 'cdate' => date("Y-m-d H:i:s"), ]; // 經由計算取得的完整 request JSON $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); // 調用 API 取得返回 $data['memoOut'] = $res; // 紀錄 $this->syslog($data); return [ 'in' => json_decode($data['memoIn']), 'out' => json_decode($data['memoOut']), ]; } public function esiFlowTagTagging() { // 本次調用的參數整理 $tid = 'f7d27d19-b05e-4ec8-bb49-2c5b0525e095'; $uid = 'Ud2534d6e1eed9cee2c919a993443352b'; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/tag/Tagging', $req); $res = $response->getBody(); // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'TagTagging', 'k' => '', 'cdate' => date("Y-m-d H:i:s"), ]; // 經由計算取得的完整 request JSON $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); // 調用 API 取得返回 $data['memoOut'] = $res; // 紀錄 $this->syslog($data); return [ 'in' => json_decode($data['memoIn']), 'out' => json_decode($data['memoOut']), ]; } public function esiFlowTagInsert() { // 本次調用的參數整理 $tag = '串門子-所有'; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'Tags' => [['Name' => $tag]], ]); //$msgRaw = preg_replace('/[\-]/', '', $msgRaw); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'Tags' => [['Name' => $tag]], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/tag/Insert', $req); $res = $response->getBody(); // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'TagInsert', 'k' => '', 'cdate' => date("Y-m-d H:i:s"), ]; // 經由計算取得的完整 request JSON $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); // 調用 API 取得返回 $data['memoOut'] = $res; // 紀錄 $this->syslog($data); return [ 'in' => json_decode($data['memoIn']), 'out' => json_decode($data['memoOut']), ]; } public function esiFlowLP() { // 共用變數 $uid = "Ub02cb4e598a7d6b3802cc6fb073ce717"; $rqidA = $this->getRqId(); $seedKey = $this->getSeedKey(); $divDataA = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divDataA); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'UID' => $uid, 'Amount' => 1, ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'ICV' => $icv, 'DivData' => $divDataA, 'MAC' => $mac, 'UID' => $uid, 'Amount' => 1, ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'LinepointIssue', 'k' => $uid, 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/linepoint/issue', $req); $resA = json_decode($response->getBody()); $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode($resA, JSON_UNESCAPED_UNICODE); $this->syslog($data); return [ 'in' => json_decode($data['memoIn']), 'out' => json_decode($data['memoOut']), ]; } public function esiFlowBak() { // 本次調用的參數整理 $uid = 'Ud2534d6e1eed9cee2c919a993443352b'; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'UID' => $uid, ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'UID' => $uid, ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/contact/QueryQualification', $req); $res = $response->getBody(); // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'QueryQualification', 'k' => $uid, 'cdate' => date("Y-m-d H:i:s"), ]; // 經由計算取得的完整 request JSON $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); // 調用 API 取得返回 $data['memoOut'] = $res; // 紀錄 $this->syslog($data); // 返回值判斷 $res = $res . json_encode($req); return $res; $rcode = $res->RCode ?? ''; if ($rcode != '0000') return false; $isfollow = $res->Result->IsFollow ?? false; $ismember = $res->Result->IsTWPMember ?? false; if (!$isfollow || !$ismember) return false; return true; } public function getSeedKey() { // 參照官方文件教學 // HEX 的 XOR 運算 $all = strtoupper(bin2hex(pack('H*', env('SEED_KEY_A')) ^ pack('H*', env('SEED_KEY_B')))); // 分為前後的 A B 兩段,而不是原先文章定義的 A B 兩個 KEY $a = substr($all, 0, strlen($all) / 2); $b = substr($all, strlen($all) / 2, strlen($all) / 2); // 最後結合的是 A-B-A 段 return $a . $b . $a; } public function getSessionKey($seedKey, $divData) { // 先將 HEX 還原成 BYTE 運算 $sessionKey = bin2hex(openssl_encrypt(hex2bin($divData), 'DES-EDE3-ECB', hex2bin($seedKey), OPENSSL_RAW_DATA)); // 按照文件擷取前 24 BYTE (也可以不用) $sessionKey = substr($sessionKey, 0, 48); // 按照文件轉成大寫 (也可以不用) $sessionKey = strtoupper($sessionKey); return $sessionKey; } public function getRqId() { $data = $data ?? random_bytes(16); assert(strlen($data) == 16); $data[6] = chr(ord($data[6]) & 0x0f | 0x40); $data[8] = chr(ord($data[8]) & 0x3f | 0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); } public function getDivData() { return bin2hex(random_bytes(24)); } public function getMsgRaw($msg) { $ret = ''; foreach ($msg as $m) { $ret .= (is_array($m)) ? json_encode($m, JSON_UNESCAPED_UNICODE) : preg_replace('/[^A-Za-z0-9\-]/', '', $m); } return $ret; } public function getMsgHash($msg) { // 返回可以大寫也可以不用 return strtoupper(hash('sha256', $msg)); } public function getICV() { return bin2hex(random_bytes(8)); } public function getMACRaw($msgHash, $sessionKey, $icv) { // 先將 HEX 還原成 BYTE 運算 (其中 ICV 可以大寫也可以不用) $macRaw = bin2hex(openssl_encrypt(hex2bin($msgHash), 'DES-EDE3-CBC', hex2bin($sessionKey), OPENSSL_RAW_DATA, hex2bin($icv))); // 返回可以大寫也可以不用 return strtoupper($macRaw); } public function getMAC($macRaw) { // 按照文件擷取前 32 BYTE (必要) $macRaw = substr($macRaw, 0, 64); // 可以大寫也可以不用 $macRaw = strtoupper($macRaw); return substr($macRaw, strlen($macRaw) - 16, 8); } // 類發票 public function setdoc($data) { // 調用 $response = $this->imgC->annotateImage( $data, [Type::TEXT_DETECTION] ); $texts = $response->getTextAnnotations(); // 整理字串 $ret = []; foreach ($texts as $text) $ret[] = $text->getDescription(); // 銀行 APP 判別 $account_bank = ''; $detect = explode("\n", $ret[0]); foreach ($detect as $d) { if ($d == '出示退款碼') $account_bank = '007'; if ($d == '登入/安控') $account_bank = '009'; if ($d == '繼續台灣 Pay交易') $account_bank = '016'; if ($d == '我要退款') $account_bank = '017'; if ($d == '繼續行動支付') $account_bank = '050'; if ($d == '完成') $account_bank = '806'; } // 整理觸發字串 $order_no = ''; $account_no = ''; $order_date = ''; switch ($account_bank) { case '007': for ($i = 0; $i < count($ret); $i++) { if ($ret[ $i ] == '訂單') $order_no = $ret[ $i + 2 ] ?? ''; if ($ret[ $i ] == '帳號') $account_no = $ret[ $i + 1 ] ?? ''; if (preg_match("/^[0-9]{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/", $ret[ $i ])) { $order_date = $ret[ $i ] ?? ''; } } break; case '009': for ($i = 0; $i < count($ret); $i++) { if ($ret[ $i ] == '訂單') $order_no = $ret[ $i + 2 ] ?? ''; if ($ret[ $i ] == '帳號') $account_no = $ret[ $i + 1 ] ?? ''; if (preg_match("/^[0-9]{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/", $ret[ $i ])) { $order_date = $ret[ $i ] ?? ''; } } break; case '016': for ($i = 0; $i < count($ret); $i++) { if ($ret[ $i ] == '訂單') $order_no = $ret[ $i + 2 ] ?? ''; if ($ret[ $i ] == '帳號') $account_no = $ret[ $i + 1 ] ?? ''; if (preg_match("/^[0-9]{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/", $ret[ $i ])) { $order_date = $ret[ $i ] ?? ''; } } break; case '017': for ($i = 0; $i < count($ret); $i++) { if ($ret[ $i ] == '訂單') $order_no = $ret[ $i + 2 ] ?? ''; if ($ret[ $i ] == '方式') $account_no = $ret[ $i + 1 ] ?? ''; if (preg_match("/^[0-9]{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/", $ret[ $i ])) { $order_date = $ret[ $i ] ?? ''; } } break; case '050': for ($i = 0; $i < count($ret); $i++) { if ($ret[ $i ] == '訂單') $order_no = $ret[ $i + 2 ] ?? ''; if ($ret[ $i ] == '帳號') $account_no = $ret[ $i + 1 ] ?? ''; // 沒有時間資訊可取得,這個是虛設 if (preg_match("/^[0-9]{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/", $ret[ $i ])) { $order_date = $ret[ $i ] ?? ''; } } break; case '806': for ($i = 0; $i < count($ret); $i++) { if ($ret[ $i ] == '編號') $order_no = $ret[ $i + 1 ] ?? ''; if ($ret[ $i ] == '商戶') $account_no = preg_replace('/-/', "", $ret[ $i - 1 ]) ?? ''; if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $ret[ $i ])) { $order_date = preg_replace('/-/', "/", $ret[ $i ]) ?? ''; } } break; case '': for ($i = 0; $i < count($ret); $i++) { if ($ret[ $i ] == '訂單') $order_no = $ret[ $i + 2 ] ?? ''; if ($ret[ $i ] == '付款' && $ret[ $i + 1 ] == '帳號') $account_bank = $ret[ $i + 2 ] ?? ''; if ($ret[ $i ] == '付款' && $ret[ $i + 1 ] == '帳號') $account_no = $ret[ $i + 4 ] ?? ''; //if ($ret[ $i ] == '時間') $order_date = $ret[ $i + 2 ] ?? ''; if (preg_match("/^[0-9]{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])$/", $ret[ $i ])) { $order_date = $ret[ $i ] ?? ''; } } break; } return [ 'order_no' => $order_no, 'account_bank' => $account_bank, 'account_no' => $account_no, 'order_date' => $order_date, //'debug' => $ret, ]; } public function activityinfo() { // 活動資訊 $activityinfo = $this->activityManagementDb ->select(['id', 'reqTimeBegin', 'reqTimeFinal']) ->where('reqTimeFinal', '>=', date("Y-m-d")) ->where('reqTimeBegin', '<=', date("Y-m-d")) ->where('isDraw', '') ->get(); if (count($activityinfo) == 0) { return false; } else { $activityinfo = $activityinfo->toArray(); } return $activityinfo; } public function activities() { // 活動資訊 $activities = $this->activityManagementDb ->select([ 'id', 'activityName', 'reqTimeBegin', 'reqTimeFinal', 'drawTime', 'drawNumbers', 'isDraw', 'redeemTimeBegin', 'redeemTimeFinal', 'isCheckBegin', 'checkTimeBegin', 'checkTimeFinal', 'getTimeBegin', 'getTimeFinal', 'isGetFinal', ]) ->get(); if (count($activities) == 0) { return false; } else { $activities = $activities->toArray(); } return $activities; } public function reqreceipt($info) { // 重複登錄資料邏輯判斷 $r = $this->receiptManagementDb ->select(['id']) ->where('lineId', $info['lineId']) ->where('lineName', $info['name']) ->where('tranDate', $info['order_date']) ->where('tranBank', \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $info['account_bank'] . "'), \"" . env('KK') . "\"))")) ->where('tranAccount', \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $info['account_no'] . "'), \"" . env('KK') . "\"))")) ->where('tranOrderNo', \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $info['order_no'] . "'), \"" . env('KK') . "\"))")) ->get(); if (count($r) == 0) return 0; // 實際寫入 $this->receiptManagementDb ->insert([ 'aid' => $info['aid'], 'tranDate' => $info['order_date'], 'tranBank' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $info['account_bank'] . "'), \"" . env('KK') . "\"))"), 'tranAccount' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $info['account_no'] . "'), \"" . env('KK') . "\"))"), 'tranOrderNo' => \DB::raw("HEX(AES_ENCRYPT(TO_BASE64('" . $info['order_no'] . "'), \"" . env('KK') . "\"))"), 'lineId' => $info['lineId'], 'lineName' => $info['name'], 'cdate' => date('Y-m-d H:i:s'), 'mdate' => date('Y-m-d H:i:s'), 'oid' => 0, // 外部用戶使用0 ]); $id = \DB::getPdo()->lastInsertId(); return $id; } public function lstreceipt($lineId) { // 依照(有限的)不同活動逐次取得該活動的所有紀錄 $activity = $this->activityManagementDb->select(['id', 'activityName'])->orderby('drawTime', 'desc')->get(); if (count($activity) == 0) { return []; } else { $activity = $activity->toArray(); } $ret = []; // 選欄位 $rStatusMsg = ''; $rStatusBtn = ''; foreach (GeneralConst::$rStatusMap as $k => $v) { $rStatusMsg .= ' when \'' . $k . '\' then \'' . $v['front'] . '\''; $rStatusBtn .= ' when \'' . $k . '\' then \'' . $v['btn'] . '\''; } // 逐個活動取得紀錄 foreach ($activity as $a) { $receipt = $this->receiptManagementDb ->select([ 'id', \DB::raw("tranDate as order_date"), \DB::raw("FROM_BASE64(AES_DECRYPT(UNHEX(tranBank), \"" . env('KK') . "\")) as account_bank"), \DB::raw("FROM_BASE64(AES_DECRYPT(UNHEX(tranAccount), \"" . env('KK') . "\")) as account_no"), \DB::raw("FROM_BASE64(AES_DECRYPT(UNHEX(tranOrderNo), \"" . env('KK') . "\")) as order_no"), 'rStatus', \DB::raw("(case rStatus $rStatusMsg end) as rStatusMsg"), \DB::raw("(case rStatus $rStatusBtn end) as rStatusBtn"), ]) ->where('lineId', $lineId) // 自己的訂單 ->where('aid', $a['id']) // 某一期的訂單 ->orderby('cdate', 'desc') ->get(); if (count($receipt) != 0) { $receipt = $receipt->toArray(); // 依照順序切分(356412978) $tmp = []; foreach ($receipt as $r) $tmp[ $r['rStatus'] ][] = $r; // 整合 $ret[] = [ 'activityName' => $a['activityName'], 'receipts' => array_merge( $tmp[ GeneralConst::RSTATUS_DRAW_DONE ] ?? [], $tmp[ GeneralConst::RSTATUS_DRAW_DONE_REDEEM_DONE ] ?? [], $tmp[ GeneralConst::RSTATUS_DRAW_DONE_REDEEM_FAIL ] ?? [], $tmp[ GeneralConst::RSTATUS_DRAW_DONE_REDEEM ] ?? [], $tmp[ GeneralConst::RSTATUS_INIT ] ?? [], $tmp[ GeneralConst::RSTATUS_DRAW_FAIL ] ?? [], $tmp[ GeneralConst::RSTATUS_DRAW_DONE_REDEEM_DONE_GET ] ?? [], $tmp[ GeneralConst::RSTATUS_DRAW_DONE_EXPIRED ] ?? [], $tmp[ GeneralConst::RSTATUS_DRAW_DONE_REDEEM_DONE_EXPIRED ] ?? [] ), ]; } } return $ret; } public function redeemCheck($lineId, $rid) { // 收據資訊 $receiptinfo = $this->receiptManagementDb ->select(['aid']) ->where('lineId', $lineId) // 找自己的 ->where('id', $rid) // 收據 ->where('rStatus', GeneralConst::RSTATUS_DRAW_DONE) // 可驗證的狀態 ->get(); if (count($receiptinfo) == 0) { return false; } else { $receiptinfo = $receiptinfo->toArray(); } // 活動資訊 $activityinfo = $this->activityManagementDb ->select(['id', 'reqTimeBegin', 'reqTimeFinal']) ->where('id', $receiptinfo[0]['aid']) // 找該收據活動 ->where('isDraw', 'Y') // 已經開獎 ->where('redeemTimeFinal', '>=', date("Y-m-d")) // 且還在可登記的時間範圍內 ->where('redeemTimeBegin', '<=', date("Y-m-d")) ->get(); if (count($activityinfo) == 0) { return false; } else { return true; } } public function redeemExecute($lineId, $rid) { $this->receiptManagementDb ->where('lineId', $lineId) ->where('id', $rid) ->where('rStatus', GeneralConst::RSTATUS_DRAW_DONE) ->update([ 'rStatus' => GeneralConst::RSTATUS_DRAW_DONE_REDEEM, 'mdate' => date('Y-m-d H:i:s'), 'oid' => 0, // 外部用戶使用0 ]); return true; } public function getCheck($lineId, $rid) { // 收據資訊 $receiptinfo = $this->receiptManagementDb ->select(['aid']) ->where('lineId', $lineId) // 找自己的 ->where('id', $rid) // 收據 ->where('rStatus', GeneralConst::RSTATUS_DRAW_DONE_REDEEM_DONE) // 可領獎的狀態 ->where('canGet', 'Y') // 可領獎的狀態(輔助狀態) ->get(); if (count($receiptinfo) == 0) { return false; } else { $receiptinfo = $receiptinfo->toArray(); } // 活動資訊 $activityinfo = $this->activityManagementDb ->select(['id', 'reqTimeBegin', 'reqTimeFinal']) ->where('id', $receiptinfo[0]['aid']) // 找該收據活動 ->where('isDraw', 'Y') // 已經開獎 ->where('getTimeFinal', '>=', date("Y-m-d")) // 且還在可領獎的時間範圍內 ->where('getTimeBegin', '<=', date("Y-m-d")) ->get(); if (count($activityinfo) == 0) { return false; } else { return true; } } public function getExecute($lineId, $rid) { try { if ($this->settingManagementSv->getSetting()['RECEIPT_ESI_LINEPOINT'] == 'true') { // 共用變數 $uid = $lineId; $rqidA = $this->getRqId(); $rqidB = $this->getRqId(); $seedKey = $this->getSeedKey(); $divDataA = $this->getDivData(); $divDataB = $this->getDivData(); // // // 1/2 打點 // // // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divDataA); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'UID' => $uid, 'Amount' => 1, ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'ICV' => $icv, 'DivData' => $divDataA, 'MAC' => $mac, 'UID' => $uid, 'Amount' => 1, ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'LinepointIssue', 'k' => $uid, 'kk' => 'activity', 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/linepoint/issue', $req); $resA = json_decode($response->getBody()); $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode($resA, JSON_UNESCAPED_UNICODE); $this->syslog($data); // // // 2/2 打點確認 // // // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divDataB); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidB, 'QueryRqid' => $rqidA, // 剛才的RQID 'UID' => $uid, ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidB, 'ICV' => $icv, 'DivData' => $divDataB, 'MAC' => $mac, 'QueryRqid' => $rqidA, // 剛才的RQID 'UID' => $uid, ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'LinepointQuery', 'k' => $uid, 'kk' => 'activity', 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/linepoint/query', $req); $resB = json_decode($response->getBody()); $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode($resB, JSON_UNESCAPED_UNICODE); $this->syslog($data); // 打點返回成功,需要確認 // 確認成功,對用戶返回已打點的資訊,也計入資料庫 // 確認失敗,對用戶返回已打點的資訊,也計入資料庫(差別只在於 LOG 註記的內容不同) // 打點返回失敗,需要確認 // 確認成功,對用戶返回已打點的資訊,也計入資料庫(差別也只在於 LOG 註記的內容不同) // 確認失敗,報錯 if ($resA->RCode != '0000' && $resB->RCode != '0000') { return false; } } // 修改資料庫狀態 $this->receiptManagementDb ->where('lineId', $lineId) ->where('id', $rid) ->where('rStatus', GeneralConst::RSTATUS_DRAW_DONE_REDEEM_DONE) ->update([ 'rStatus' => GeneralConst::RSTATUS_DRAW_DONE_REDEEM_DONE_GET, 'mdate' => date('Y-m-d H:i:s'), 'oid' => 0, // 外部用戶使用0 ]); } catch (Exception $ex) { // 錯誤可能發生在 memoIn 或是 out $data['memoIn'] = json_encode(['error' => 'exception'], JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode(['code' => $ex->getCode(), 'msg' => $ex->getMessage()], JSON_UNESCAPED_UNICODE); $this->syslog($data); return false; } return true; } // 串門子 public function tplayerinfo($lineId) { // 取得用戶在本地的資訊 $tplayerinfo = $this->tplayerManagementDb ->select(['id']) ->where('lineId', $lineId) ->get() ->toArray(); // 取得用戶在 LINE 上的 profile // $profile = $this->lineProfile($lineId); if (count($tplayerinfo) == 0) { // 用戶不在本地資料庫,新增 // 寫入資料表 $d = [ 'lineId' => $lineId, 'userName' => '', 'userPhoto' => '', 'c1' => 0, 'c2' => 0, 'c3' => 0, 'c4' => 0, 'c5' => 0, 'c6' => 0, 'c7' => 0, 'c8' => 0, 'c9' => 0, 'gp' => 0, 'cdate' => date("Y-m-d H:i:s"), 'mdate' => date("Y-m-d H:i:s"), ]; $this->tplayerManagementDb ->insert($d); $id = \DB::getPdo()->lastInsertId(); // 替用互打一次性標籤 $this->tplayerTag($lineId); } else { // 用戶的 LINE 資訊可能會更新,所以這個 API 還身兼更新資訊的功能 // $d = [ // 'userName' => $profile->displayName, // 'userPhoto' => $profile->pictureUrl, // ]; // $this->tplayerManagementDb // ->where('lineId', $lineId) // ->update($d); } // 再重新查一遍 $tplayerinfo = $this->tplayerManagementDb ->select([ // 'id', 'lineId', // 'userName', // 'userPhoto', 'gp', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', \DB::raw("FLOOR(gp / " . $this->settingManagementSv->getSetting()['TMZ_GP_DRAW'] . ") as draw"), // 'cdate', // 'mdate', ]) ->where('lineId', $lineId) ->first() ->toArray(); return $tplayerinfo; } public function tplayerTag($lineId) { try { // 本次調用的參數整理 $tid = $this->settingManagementSv->getSetting()['TMZ_CURRENT_TAG']; $uid = $lineId; $rqid = $this->getRqId(); // 取得 seedKey $seedKey = $this->getSeedKey(); // 隨機產生多樣性資料 $divData = $this->getDivData(); // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divData); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqid, 'ICV' => $icv, 'DivData' => $divData, 'MAC' => $mac, 'TagInfos' => [ [ 'Tagid' => $tid, 'UIDs' => [$uid] ], ], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'TagTagging', 'k' => $uid, 'kk' => 'tmz', 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/tag/Tagging', $req); $res = $response->getBody(); // 經由計算取得的完整 request JSON $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); // 調用 API 取得返回 $data['memoOut'] = $res; // 紀錄 $this->syslog($data); } catch (Exception $ex) { // 錯誤可能發生在 memoIn 或是 out $data['memoIn'] = json_encode(['error' => 'exception'], JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode(['code' => $ex->getCode(), 'msg' => $ex->getMessage()], JSON_UNESCAPED_UNICODE); $this->syslog($data); return false; } return true; } public function tcheckin($lineId, $name) { // 回合資訊 $troundinfo = $this->troundManagementDb ->select(['id']) ->where('dateFinal', '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get() ->toArray(); // 一定有回合所以不防呆(參考本函數註解) // 依照簽到狀態決定需不需要簽到 & 決定簽到吉點 $playinfo = $this->tsessionManagementDb ->select(['currentCheckinGp', 'eventDate']) ->where('lineId', $lineId) ->where('rid', $troundinfo[0]['id']) ->where('gid', '=', -1) // 僅篩選簽到 ->get() ->toArray(); $cancheckin = true; $checkins = 0; // 本回合不含這一次,共簽到過幾次 foreach ($playinfo as $p) { // 檢驗當天是否有簽到 if ($p['eventDate'] == date("Y-m-d")) { if ($p['currentCheckinGp'] >= 0) $cancheckin = false; } // 統計本回合已簽到過幾次 if ($p['currentCheckinGp'] >= 0) { $checkins++; } } //if ($lineId == $this->settingManagementSv->getSetting()['GAME_TESTING_LINE_ID']) $checkins = 0; $currentCheckinGp = ($cancheckin) ? $this->getGpByTCheckins($checkins + 1) : 0; // 拼湊 tsession 紀錄 $currentGp = $currentCheckinGp; $res = [ 'pid' => $this->getTPidBylineId($lineId), 'lineId' => $lineId, 'userName' => $name, 'rid' => $troundinfo[0]['id'], 'gid' => -1, // 簽到專用 'cid' => 0, 'eventDate' => date("Y-m-d"), 'currentGp' => $currentGp, 'currentGameGp' => 0, 'currentCheckinGp' => $currentCheckinGp, 'cdate' => date('Y-m-d H:i:s'), ]; // 重複簽到不會有點數 if ($currentGp > 0) { $this->tsessionManagementDb->insert($res); $id = \DB::getPdo()->lastInsertId(); $res['id'] = $id; // 上檔玩家吉點計算 $res['gp'] = $this->addGpToTPlayer($lineId, $currentGp); } return $res; } public function getGpByTCheckins($checkins) { $info = $this->tcheckinManagementDb->select(['gp'])->where('day', $checkins)->first()->toArray(); return $info['gp']; } public function getTPidBylineId($lineId) { $info = $this->tplayerManagementDb->select(['id'])->where('lineId', $lineId)->first()->toArray(); return $info['id']; } public function troundinfo($lineId) { // 回合資訊 $troundinfo = $this->troundManagementDb ->select(['id', 'dateBegin', 'dateFinal']) ->where('dateFinal', '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get(); if (count($troundinfo) == 0) { return false; } else { $troundinfo = $troundinfo->toArray(); } // 簽到資訊 $checkininfo = $this->tsessionManagementDb ->select(['eventDate', 'currentGameGp']) ->where('lineId', $lineId) ->where('rid', $troundinfo[0]['id']) ->where('gid', '=', -1) // 僅篩選簽到 ->orderby('id', 'asc') // 確保按照時間排 ->get() ->toArray(); // 整理 $res = [ 'dateBegin' => $troundinfo[0]['dateBegin'], 'dateFinal' => $troundinfo[0]['dateFinal'], 'today' => date("Y-m-d"), 'checkins' => [], ]; foreach ($checkininfo as $c) { // 相同天可能會有重新再玩,因此會有超過1筆資料的可能,不想使用 SQL group by 耗能 $res['checkins'][ $c['eventDate'] ] = [ 'date' => $c['eventDate'], ]; } $res['checkins'] = array_values($res['checkins']); return $res; } public function addGpToTPlayer($lineId, $gp) { $info = $this->tplayerManagementDb->select(['gp'])->where('lineId', $lineId)->first()->toArray(); $gp += $info['gp']; $this->tplayerManagementDb->where('lineId', $lineId)->update(['gp' => $gp]); return $gp; } public function isTPlayer($lineId) { $tplayerinfo = $this->tplayerManagementDb->select(['id'])->where('lineId', $lineId)->get()->toArray(); return (count($tplayerinfo) > 0); } public function playTGame($lineId, $name, $c) { // 回合資訊 $troundinfo = $this->troundManagementDb ->select(['id']) ->where('dateFinal', '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get() ->toArray(); // 一定有回合所以不防呆(參考本函數註解) // 檢查本回合玩過沒(同時看 tsession & tplayer,順便取得上檔九宮格分布) $playinfo = $this->tsessionManagementDb ->select(['currentCheckinGp', 'eventDate']) ->where('lineId', $lineId) ->where('rid', $troundinfo[0]['id']) ->where('gid', '=', $c) // 僅篩選九宮格的這一格 ->get(); if (count($playinfo) > 0) return false; // 本周期玩過了 $playinfo = $this->tplayerManagementDb ->select(['c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9']) ->where('lineId', $lineId) ->first() ->toArray(); $s = []; foreach ($playinfo as $k => $v) { if ('c' . $c == $k && $v != 0) return false; // 本周期玩過了 $s[ $k ] = $v; } // 依照九宮格分布計算本次應得吉點,以及紀錄九宮格狀態變遷 $gp = 1; // 答對本來就有1點 $s[ 'c' . $c ] = 2; // 答對初始狀態 switch ($c) { case 1: if ($playinfo['c2'] != 0 && $playinfo['c3'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c2'] = 3; $s['c3'] = 3; } if ($playinfo['c4'] != 0 && $playinfo['c7'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c4'] = 3; $s['c7'] = 3; } if ($playinfo['c5'] != 0 && $playinfo['c9'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c5'] = 3; $s['c9'] = 3; } break; case 2: if ($playinfo['c1'] != 0 && $playinfo['c3'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c1'] = 3; $s['c3'] = 3; } if ($playinfo['c5'] != 0 && $playinfo['c8'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c5'] = 3; $s['c8'] = 3; } break; case 3: if ($playinfo['c1'] != 0 && $playinfo['c2'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c1'] = 3; $s['c2'] = 3; } if ($playinfo['c6'] != 0 && $playinfo['c9'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c6'] = 3; $s['c9'] = 3; } if ($playinfo['c5'] != 0 && $playinfo['c7'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c5'] = 3; $s['c7'] = 3; } break; case 4: if ($playinfo['c1'] != 0 && $playinfo['c7'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c1'] = 3; $s['c7'] = 3; } if ($playinfo['c5'] != 0 && $playinfo['c6'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c5'] = 3; $s['c6'] = 3; } break; case 5: if ($playinfo['c4'] != 0 && $playinfo['c6'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c4'] = 3; $s['c6'] = 3; } if ($playinfo['c2'] != 0 && $playinfo['c8'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c2'] = 3; $s['c8'] = 3; } if ($playinfo['c1'] != 0 && $playinfo['c9'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c1'] = 3; $s['c9'] = 3; } if ($playinfo['c3'] != 0 && $playinfo['c7'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c3'] = 3; $s['c7'] = 3; } break; case 6: if ($playinfo['c3'] != 0 && $playinfo['c9'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c3'] = 3; $s['c9'] = 3; } if ($playinfo['c4'] != 0 && $playinfo['c5'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c4'] = 3; $s['c5'] = 3; } break; case 7: if ($playinfo['c8'] != 0 && $playinfo['c9'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c8'] = 3; $s['c9'] = 3; } if ($playinfo['c1'] != 0 && $playinfo['c4'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c1'] = 3; $s['c4'] = 3; } if ($playinfo['c3'] != 0 && $playinfo['c5'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c3'] = 3; $s['c5'] = 3; } break; case 8: if ($playinfo['c2'] != 0 && $playinfo['c5'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c2'] = 3; $s['c5'] = 3; } if ($playinfo['c7'] != 0 && $playinfo['c9'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c7'] = 3; $s['c9'] = 3; } break; case 9: if ($playinfo['c7'] != 0 && $playinfo['c8'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c7'] = 3; $s['c8'] = 3; } if ($playinfo['c3'] != 0 && $playinfo['c6'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c3'] = 3; $s['c6'] = 3; } if ($playinfo['c1'] != 0 && $playinfo['c5'] != 0) { $gp += 3; $s[ 'c' . $c ] = 3; $s['c1'] = 3; $s['c5'] = 3; } break; } // 拼湊 tsession 紀錄 $currentGp = $gp; $res = [ 'pid' => $this->getTPidBylineId($lineId), 'lineId' => $lineId, 'userName' => $name, 'rid' => $troundinfo[0]['id'], 'gid' => $c, 'cid' => 0, 'eventDate' => date("Y-m-d"), 'currentGp' => $currentGp, 'currentGameGp' => $currentGp, 'currentCheckinGp' => 0, 'cdate' => date('Y-m-d H:i:s'), ]; $this->tsessionManagementDb->insert($res); $id = \DB::getPdo()->lastInsertId(); $res['id'] = $id; // 上檔玩家吉點計算+九宮格布局修改 $res['gp'] = $this->addGpAndJggToTPlayer($lineId, $currentGp, $s); return $res; } public function addGpAndJggToTPlayer($lineId, $gp, $jgg) { // 計算增加後的吉點 $info = $this->tplayerManagementDb->select(['gp'])->where('lineId', $lineId)->first()->toArray(); $gp += $info['gp']; $d = ['gp' => $gp]; $d = array_merge($d, $jgg); // 更新 $this->tplayerManagementDb->where('lineId', $lineId)->update($d); return $d; } public function tredeeminfo($lineId) { $tplayerinfo = $this->tplayerManagementDb ->select(['gp']) ->where('lineId', $lineId) ->first() ->toArray(); return ($tplayerinfo['gp'] >= $this->settingManagementSv->getSetting()['TMZ_GP_DRAW']); } public function redeemTGood($lineId, $name) { $redeeminfo = []; try { // 回合資訊 (注意用於兌獎資訊的日期區間判定與玩遊戲不同) $troundinfo = $this->troundManagementDb ->select(['id']) ->where(\DB::raw("DATE_ADD(dateFinal, INTERVAL +redeemExtra DAY)"), '>=', date("Y-m-d")) ->where('dateBegin', '<=', date("Y-m-d")) ->where('active', '=', GeneralConst::ACTIVE_YES) ->get() ->toArray(); // 來到這邊代表一定有資料 // 準備轉蛋資訊 $tgoodinfo = $this->tgoodManagementDb ->select([ 'id', // 回寫用 'ratio', // 抽獎製造冗餘資料用 'active', // 'lp', // 'totalQty', // 'issuedQty', // ]) ->where('active', 'Y') ->get() ->toArray(); $tgoodArr = []; foreach ($tgoodinfo as $g) for ($i = 0; $i < $g['ratio']; $i++) $tgoodArr[] = ['id' => $g['id'], 'lp' => $g['lp'], 'totalQty' => $g['totalQty'], 'issuedQty' => $g['issuedQty'], 'active' => $g['active']]; shuffle($tgoodArr); $tgoodinfo = $tgoodArr[0]; // good 準備資料 $fromIssuedQty = $tgoodinfo['issuedQty']; $toIssuedQty = $fromIssuedQty + 1; // player 準備資料 $tplayerinfo = $this->tplayerManagementDb->select(['gp'])->where('lineId', $lineId)->first()->toArray(); $fromGp = $tplayerinfo['gp']; $toGp = $tplayerinfo['gp'] - $this->settingManagementSv->getSetting()['TMZ_GP_DRAW']; // 所有銘謝惠顧的可能(獎項雖然有點數但已被兌換完畢 || 獎項被設定為未啟用) if ( $tgoodinfo['totalQty'] - $tgoodinfo['issuedQty'] <= $this->settingManagementSv->getSetting()['TMZ_ISSUE_BUFFER'] || $tgoodinfo['active'] == GeneralConst::ACTIVE_NO ) { $this->debuglog('redeemTGood', [ 'msg' => '所有銘謝惠顧的可能' ]); return false; } // 銘謝惠顧獎項還是要扣除集點,所以不能返回錯誤,只是需要先控制不要進入直通 // 直通打點與確認 (先打點,依照返回正確與否再決定要不要後續操作本地資料) if ($this->settingManagementSv->getSetting()['TMZ_ESI_LINEPOINT'] == 'true' && $tgoodinfo['lp'] > 0) { // 共用變數 $uid = $lineId; $rqidA = $this->getRqId(); $rqidB = $this->getRqId(); $seedKey = $this->getSeedKey(); $divDataA = $this->getDivData(); $divDataB = $this->getDivData(); // // // 1/2 打點 // // // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divDataA); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'UID' => $uid, 'Amount' => $tgoodinfo['lp'], ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidA, 'ICV' => $icv, 'DivData' => $divDataA, 'MAC' => $mac, 'UID' => $uid, 'Amount' => $tgoodinfo['lp'], ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'LinepointIssue', 'k' => $uid, 'kk' => 'tmz', 'cdate' => date("Y-m-d H:i:s"), ]; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/linepoint/issue', $req); $resA = json_decode($response->getBody()); $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode($resA, JSON_UNESCAPED_UNICODE); $this->syslog($data); // // // 2/2 打點確認 // // // 產生本次調用的 sessionKey $sessionKey = $this->getSessionKey($seedKey, $divDataB); // 整理押碼用的資料欄內容 $msgRaw = $this->getMsgRaw([ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidB, 'QueryRqid' => $rqidA, // 剛才的RQID 'UID' => $uid, ]); $msgHash = $this->getMsgHash($msgRaw); // 建立ICV $icv = $this->getICV(); // 建立押碼 $macRaw = $this->getMACRaw($msgHash, $sessionKey, $icv); $mac = $this->getMAC($macRaw); // 參數打包 $param = [ 'RqClient' => env('RQ_CLIENT'), 'RqId' => $rqidB, 'ICV' => $icv, 'DivData' => $divDataB, 'MAC' => $mac, 'QueryRqid' => $rqidA, // 剛才的RQID 'UID' => $uid, ]; // 相關中繼資料打包(LOG 用) $logdata = [ 'sessionKey' => $sessionKey, 'msgRaw' => $msgRaw, 'msgHash' => $msgHash, 'macRaw' => $macRaw, ]; // 憑證參數整理 $curlparam = [ CURLOPT_SSLCERTTYPE => 'PEM', CURLOPT_SSLCERT => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_pub.pem', CURLOPT_SSLKEYTYPE => 'PEM', CURLOPT_SSLKEY => env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_key.pem', CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ]; if (env('CERT_PASS') != '') $curlparam[ CURLOPT_KEYPASSWD ] = env('CERT_PASS'); if (env('CERT_PASS') != '') $curlparam[ CURLOPT_CAINFO ] = env('LOCAL_PATH') . 'cert/' . env('APP_ENV') . '_ca.pem'; // 調用 $req = [ 'curl' => $curlparam, 'body' => json_encode($param, JSON_UNESCAPED_UNICODE), 'headers' => [ 'Content-Type' => 'application/json', 'User-Agent' => 'ogilvy-' . env('APP_ENV'), 'Accept' => '*/*', ] ]; if (!in_array($_SERVER['SERVER_ADDR'], ['172.31.30.167', '172.31.9.233', '172.31.42.197', '172.31.34.163'])) $req['proxy'] = env('CCH_PROXY'); $response = $this->c->request('POST', env('API_BASE') . '/line/api/twpapi/linepoint/query', $req); $resB = json_decode($response->getBody()); // 直通紀錄 $data = [ 'type' => GeneralConst::LOG_ESI, 'func' => 'LinepointQuery', 'k' => $uid, 'kk' => 'tmz', 'cdate' => date("Y-m-d H:i:s"), ]; $data['memoIn'] = json_encode(array_merge($param, $logdata), JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode($resB, JSON_UNESCAPED_UNICODE); $this->syslog($data); // 打點返回成功,需要確認 // 確認成功,對用戶返回已打點的資訊,也計入資料庫 // 確認失敗,對用戶返回已打點的資訊,也計入資料庫(差別只在於 LOG 註記的內容不同) // 打點返回失敗,需要確認 // 確認成功,對用戶返回已打點的資訊,也計入資料庫(差別也只在於 LOG 註記的內容不同) // 確認失敗,報錯 if ($resA->RCode != '0000' && $resB->RCode != '0000') { $this->debuglog('redeemTGood', [ 'msg' => '打點返回失敗,需要確認' ]); return false; } } // session 插入 $res = [ 'pid' => $this->getTPidBylineId($lineId), 'lineId' => $lineId, 'userName' => $name, 'rid' => $troundinfo[0]['id'], 'gid' => 0, 'cid' => $tgoodinfo['id'], // 獎項的 ID 'eventDate' => date("Y-m-d"), 'currentGp' => -$this->settingManagementSv->getSetting()['TMZ_GP_DRAW'], 'currentGameGp' => 0, 'currentCheckinGp' => 0, 'cdate' => date('Y-m-d H:i:s'), ]; $this->tsessionManagementDb->insert($res); // good 更新資料 $this->tgoodManagementDb->where('id', $tgoodinfo['id'])->update(['issuedQty' => $toIssuedQty]); // tplayer 更新資料 $this->tplayerManagementDb->where('lineId', $lineId)->update(['gp' => $toGp]); // 整理本地紀錄資料 $redeeminfo = [ 'playerinfo' => [ 'lineId' => $lineId, 'fromGp' => $fromGp, 'toGp' => $toGp, ], 'redeeminfo' => [ 'id' => $tgoodinfo['id'], 'lp' => $tgoodinfo['lp'], 'fromIssuedQty' => $fromIssuedQty, 'toIssuedQty' => $toIssuedQty, ], 'session' => $res, ]; } catch (Exception $ex) { // 錯誤可能發生在 memoIn 或是 out $data['memoIn'] = json_encode(['error' => 'exception'], JSON_UNESCAPED_UNICODE); $data['memoOut'] = json_encode(['code' => $ex->getCode(), 'msg' => $ex->getMessage()], JSON_UNESCAPED_UNICODE); $this->syslog($data); $this->debuglog('redeemTGood', [ 'rqidA' => $rqidA ?? 0, 'rqidB' => $rqidB ?? 0 ], [ 'errCode' => $ex->getCode(), 'requestTime' => $requestTime ?? '', 'logTime' => date("Y-m-d H:i:s"), 'errMsg' => $ex->getMessage(), ]); return false; } return $redeeminfo; } }