我喜歡二次元

我喜歡二次元, 是因為我喜歡那個世界, 我為他們的純真而感動, 為他們的夢想所激勵, 為他們的堅持所鼓舞, 那些夢幻的,可能存在的或不可能存在的美好, 很多我在三次元世界裡已經找不到了, 我多麼想穿越次元的隧道, 與我所愛的人一起, 因為無法穿越, 讓我總在二次元與三次元中徘徊, 無論我多麼愛你, 我還是要說一聲對不起, 因為我活在三次元……

2019年5月20日 · 1 min · MoeJue

小程序架構

不知道大家們寫小程序是怎麼個寫法的,前幾個月在寫微信小程序,自己整理的一種架構,或者叫框架 微信原生的架構是這樣子 ├── app.js ├── app.json ├── app.wxss ├── pages │ │── index │ │ ├── index.wxml │ │ ├── index.js │ │ ├── index.json │ │ └── index.wxss │ └── logs │ ├── logs.wxml │ └── logs.js └── utils 為什麼不用微信原生的寫法呢? 小程序就類似手機APP,都會有一個tabBar欄對吧,微信官方的tabBar欄是在app.json中進行的全局配置。做一般的開發是沒有任何問題的,但涉及到一個複雜的tabBar欄時,使用官方原生的就無法實現,也無法動態載入,比如某影片app中間的拍照錄影功能 這意味著,我們不能使用官方給我們提供的tabBar欄,需要我們自己寫 最開始我的做法還是保持原生的結構,只是自己寫tabBar欄,所以頁面程式碼都寫在一個文件中,預設顯示第一屏,其他的都隱藏起來,切換頁面的時候再把相應的頁面顯示,其他的隱藏起來,並且動態渲染資料上去。但是有個問題是,如果是小專案倒沒什麼大問題,但是如果是大專案程式碼量非常龐大,都寫在一個文件中,後期難以維護,所以這個方法最後被pass掉 再後來將切換頁面的方式改為跳轉(wx.switchTab等),把不同頁面的程式碼放到了不同的文件,但是還有一個問題,切換也會閃爍,每次切換頁面就等於重新打開一個網頁一樣,tabBar都被重新渲染,所以會閃爍。pass 由此就有了現在的全新架構方式: 將/pages/index/下的文件全部定義為入口文件,js入口,css入口,視圖入口,不同頁面的文件還是放到不同的位置去,為了好管理,新建了一個template的資料夾,用於放不同頁面間的程式碼,結構和官方的單頁面結構是一樣的 根目錄下的app.js用於存放全域函數,其他頁面呼叫只需getApp()即可 js的入口文件 const app = getApp(); var index\_js = require("../../template/index/index.js"); var types\_js = require("../../template/types/types.js"); var Global\_Data = \[\]; Page({ data: { active: 0, show: { index: true, types: false, course: false, user: false } }, onLoad(options) { this.setData({ Global\_Data: index\_js.getData() }) }, // 底部nav切换 tabbar\_onChange(event) { var key = ''; this.data.show = { index: false, types: false, course: false, user: false }; console.log(event) switch (event.detail) { case 0: key = 'index'; Global\_Data = index\_js.getData(); break; case 1: key = 'types'; Global\_Data = types\_js.getData() break; case 2: key = 'course'; Global\_Data = index\_js.getData(); break; case 3: key = 'user'; Global\_Data = index\_js.getData(); break; } this.data.show\[key\] = true; console.log(Global\_Data) this.setData({ show: this.data.show, Global\_Data: Global\_Data }) }, }); wxml入口文件 ...

2019年5月17日 · 2 min · MoeJue

如何優雅地提交一個表單

這是一個非常基礎的HTML表單提交問題,但卻是一個非常實用的技巧 我的業務場景是這樣的: 一個可動態建立input的表單,如下圖 這意味著input的name不能是一個固定的,否則肯定會被覆蓋掉的 第一種,傳統的普通提交方式,給每一個要提交的input一個唯一的name ...... 瀏覽器提交抓到的格式是這樣子的 伺服器獲取列印出來的是這樣的,對後端的資料處理就非常不友善 第二種,陣列的方式進行表單提交 ...... 瀏覽器和後端列印的結果分別為 細心觀察就會發現,提交的name值發生了變化,變成了一樣的?陣列? 提交到後端就會發現資料比之前整齊多了 但這裡要注意的是,提交的陣列鍵中不需要使用引號,否則引號也會成為鍵的一部分 當然了,實際中還可能遇到這樣的問題,要提交的組數(像上面的1、2、3)是不確定的,可以在前端隨意地添加,這個時候怎麼去用陣列提交這些內容呢? 下面就是我業務中的實際解決方案 這樣的話,二維陣列的鍵則不需要我們自己去維護了,由瀏覽器幫我們自動生成 後端接收到的資料則變成了這樣子,變得非常好處理了 此方法適用於,要提交一堆不確定個數的一組相關的資料對 完結撒花!~

2019年5月6日 · 1 min · MoeJue

生活為什麼總是對我動手?

穿著睡衣出門取外賣, 不想遇到熟人,偏偏被好多熟人看見; 看電影時昏昏欲睡, 中途上個廁所,就錯過高光片段; 在景區排隊買票, 不管排到哪一邊,另一邊總是走得更快…更不用說每次下雨不帶傘,帶傘時卻不下雨, 剛買東西就降價,一翹課就被點名, 想抽的卡抽不到,喜歡的人不喜歡你了…生活為什麼總對我動手? 不是命中註定,全因「墨菲定律」。 墨菲定律 一件事情無論機率有多小, 總會有發生的可能, 而你越擔心某種情況發生, 它就越有可能發生。 正如俗話說的, 你越怕什麼,就越來什麼。 就像網站越做越好了,擔心樹大招風, 果然就遭到DDoS、CC攻擊; 伺服器還在「裸奔」,怕被駭客盯上, 一不留神,就被木馬、病毒深度「捆綁」; 憂心業務安全,每天謹小慎微, 沒曾想,還是因為操作失誤丟了數據…為什麼總是會出現這些問題? 因為機率本身就是一種「玄學」, 像前沿數據事件、程式設計師刪庫跑路事件, 在發生之前誰也無法預測, 可一旦碰上,就是100%,打擊也尤為致命… 而令人遺憾的是,這些後果本來是可以避免的…試想一下,如果你提前做好了安全防禦, DDoS、CC就無法擊潰你; 而部署了防火牆、打了系統補丁, 駭客也不會有可乘之機; 再極端一點,即使程式設計師刪庫跑路了, 只要快照備份還在,也能有迴轉餘地… 所以,即使是對於小機率的「危險」事件, 我們同樣不能忽視, 做好一切的準備, 才能確保99%的安全,避免1%的損害。大規模流量攻擊來了, 有DDoS高防/ BGP高防IP隔離入侵, 遇到網頁篡改、訪問緩慢問題, 找web應用防火牆、CDN加速搞定; 而數據安全和通訊加密,交給雲硬碟、SSL憑證就行如果以上幾點你都能做到, 那麼恭喜,網站安全的flag已經摘取, 即使不幸「中招」, 也可以放寬心態,無所畏懼了

2019年4月22日 · 1 min · MoeJue

泳裝妹子果然棒

不起眼女主角培育法 – 英梨梨 – 簡稱黃毛 郵政小包 開箱 外殼轉一圈,外殼也值得收藏 看到了點不得了的東西 開箱取出,泳裝好像沒穿好,這。。。(捂眼)少兒不宜,打碼打碼 好不容易幫妹子穿好了泳裝 這腿好白,舔 轉一圈 小虎牙真棒 角度刁鑽 第一人稱(笑-。- 開箱結束,完美Ψ( ̄∀ ̄)Ψ

2019年4月19日 · 1 min · MoeJue

一些常見功能的查詢sql

1、情境:查詢一位選手的排名及距離上一名差多少票 方法二(去重排序查詢比自己少的數量) $temp = DB::fetch_first("SELECT distinct total+jewel_vote+forge_vote ,COUNT(*)+1 AS RANK FROM " . DB::table('vote_competition') ." WHERE total+jewel_vote+forge_vote>" . $competition['all'] . " and aid={$aid} ORDER by forge_vote desc"); $rank = $temp['RANK']; // 無法直接查詢到上一名選手票數 if ($temp['total+jewel_vote+forge_vote']) { // 這裡查詢出來的是和第一名選手相差的票數 $up = $temp['total+jewel_vote+forge_vote']-$competition['all']; } 方法一(定義變數累加排序) $temp = DB::fetch_all("SELECT a.cid,a.total,a.forge_vote,a.jewel_vote,(@rowNum:=@rowNum+1) AS rank FROM pre_vote_competition AS a, (SELECT (@rowNum :=0) ) b WHERE aid={$aid} ORDER BY (a.total+a.forge_vote+a.jewel_vote) DESC "); foreach ($temp as $key => $value) { if ($value['cid'] == $cid) { // 當前自己的排名 $rank = $value['rank']; if ($up) { $up = $up - ($value['total'] + $value['forge_vote'] + $value['jewel_vote']); } break; } // 和上一名選手相差的票數 $up = $value['total'] + $value['forge_vote'] + $value['jewel_vote']; } 2、情境:查詢一篇文章的上一篇和下一篇,支援斷號 ...

2019年4月10日 · 3 min · MoeJue

微信授權登入

文件:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319 微信的授權登入與QQ、新浪等平台的授權登入大同小異,均採用OauthOAuth2.0鑑權方式。 微信授權分為兩種: 靜默授權 彈窗授權,需要用戶手動同意 兩種scope的區別說明 以snsapi_base為scope發起的網頁授權,是用來獲取進入頁面的用戶openid的,並且是靜默授權並自動跳轉到回調頁的。用戶感知的就是直接進入了回調頁(往往是業務頁面) 以snsapi_userinfo為scope發起的網頁授權,是用來獲取用戶的基本資訊的。但這種授權需要用戶手動同意,並且由於用戶同意過,所以無須關注,就可在授權後獲取該用戶的基本資訊。 用戶管理類介面中的「獲取用戶基本資訊介面」,是在用戶和公眾號產生訊息交互或關注後事件推送後,才能根據用戶OpenID來獲取用戶基本資訊。這個介面,包括其他微信介面,都是需要該用戶(即openid)關注了公眾號後,才能呼叫成功的。 具體而言,網頁授權流程分為四步: 引導用戶進入授權頁面同意授權,獲取code 透過code換取網頁授權access_token(與基礎支援中的access_token不同) 如果需要,開發者可以重新整理網頁授權access_token,避免過期 透過網頁授權access_token和openid獲取用戶基本資訊(支援UnionID機制) 以下是封裝的微信操作類,需要用到兩個資料表,用於保存access_token、ticket,由於它們具有一定有效期,且每天請求數有上限,所以開發者需自行保存 <?php /\*\* \* 微信操作表 \* wxtoken 表結構 \* id \* access\_token \* addtime \* wxticket 表結構 \* id \* ticket \* addtime \*/ class WX { private $appid; private $appserect; private $curl; private $msg; protected $errs = array( '-1' => '系統繁忙,此時請開發者稍候再試', '0' => '請求成功', '40001' => 'AppSecret錯誤或者AppSecret不屬於這個公眾號,請開發者確認AppSecret的正確性', '40002' => '請確保grant\_type字段值為client\_credential', '40164' => '呼叫介面的IP地址不在白名單中,請在介面IP白名單中進行設定。', ); function \_\_construct($appid, $appserect) { $this->appid = $appid; $this->appserect = $appserect; $this->curl = new Curl(); } /\* 微信網頁授權登入 需要在公眾號設定 - 功能設定 - 網頁授權域名 第一步:用戶同意授權,獲取code scope : snsapi\_base 只能獲取openid 直接跳轉 snsapi\_userinfo \*/ public function getCode($redirect\_uri, $scope = 'snsapi\_userinfo',$state = '1') { $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect\_uri={$redirect\_uri}&response\_type=code&scope={$scope}&state={$state}#wechat\_redirect"; header("Location:{$url}"); exit; } /\* 第二步:透過code換取網頁授權access\_token \*/ public function getAccessTokenByCode($code) { $url = "https://api.weixin.qq.com/sns/oauth2/access\_token?appid={$this->appid}&secret={$this->appserect}&code={$code}&grant\_type=authorization\_code"; // exit($url); // $curl = new Curl(); $result = $this->curl->doGet($url); if (!$result) { // $this->curl->getError() $this->msg = "獲取token失敗"; return false; } $result = json\_decode($result, true); if ($result\['errcode'\]) { $this->msg = $result\['errmsg'\]; return false; } return $result; } // 第三步:重新整理access\_token(如果需要) 透過code 獲取openid $type 0靜默授權 1彈窗授權 public function getUserInfo($code, $type = 0, $lang = 'zh\_CN ') { $result = $this->getAccessTokenByCode($code); if (!$result) { return false; } $member = C::t(PT\_USER)->getByOpenid($result\['openid'\]); if ($member) { return $member; } else { if ($type) { $url = "https://api.weixin.qq.com/sns/userinfo?access\_token={$result\['access\_token'\]}&openid={$result\['openid'\]}&lang={$lang}"; // $return = $this->curl->doGet($url); // 這介面有病 強制顯示文件頭 $return = file\_get\_contents($url); if (!$return) { $this->msg = '獲取用戶資訊失敗'; return false; } $return = json\_decode($return, true); if (!$return) { $this->msg = '獲取用戶資訊返回失敗'; return false; } // file\_put\_contents('ccc.txt',print\_r($return,true),FILE\_APPEND); $data = array( 'openid' => $return\['openid'\], 'name' => $return\['nickname'\], 'sex' => $return\['sex'\], 'province' => $return\['province'\], 'city' => $return\['city'\], 'country' => $return\['country'\], 'img' => $return\['headimgurl'\], 'bindtel' => 0, ); } else { $data = array( 'openid' => $result\['openid'\], 'username' => "微信用戶\_" . random(6,1) ); } $name = rand(100000, 1000000000); $e = $name . "@qq.com"; $password = $e; $id = UserAddEdit(0, $data\['username'\], $password, $e,10,0,"", $msg); if ($id <= 0) { $this->msg = $msg; return false; } C::t(PT\_USER)->update($data, $id); $member = C::t(PT\_USER)->get($id); return $member; } } /\* 公眾號 安全中心 設定IP白名單 公眾號的全局唯一介面呼叫憑據,公眾號呼叫各介面時都需使用access\_token。開發者需要進行妥善保存。access\_token的儲存至少要保留512個字符空間。access\_token的有效期目前為2個小時,需定時重新整理,重複獲取將導致上次獲取的access\_token失效。 \*/ public function getAccessToken($type) { $addtime = TIMESTAMP - 7200; $url = "https://api.weixin.qq.com/cgi-bin/token?grant\_type=client\_credential&appid={$this->appid}&secret={$this->appserect}"; $row = C::t(PT\_WXTOKEN)->getNew($addtime, $type); if ($row) { return $row\['access\_token'\]; } else { $result = $this->curl->doGet($url); if (!$result) { $this->msg = "無法獲取令牌內容"; return false; } $result = json\_decode($result, true); if (!$result) { $this->msg = "解析令牌內容失敗"; return false; } if ($result\['access\_token'\]) { C::t(PT\_WXTOKEN)->addToken($result\['access\_token'\], $type); return $result\['access\_token'\]; } else { $this->msg = "獲取令牌失敗"; return false; } } } // 獲取js票據 需要在公眾號設定 - 功能設定 - JS介面安全域名設定 public function getJsTicket() { $addtime = TIMESTAMP - 7200; $row = C::t(PT\_WXTICKET)->getNew($addtime); if ($row) { return $row\['ticket'\]; } else { $token = $this->getAccessToken(); if (!$token) { return false; } $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access\_token={$token}&type=jsapi"; $result = $this->curl->doGet($url); if (!$result) { $this->msg = "無法獲取js票據"; return false; } $result = json\_decode($result, true); if (!$result) { $this->msg = "解析js票據內容失敗"; return false; } if ($result\['ticket'\]) { C::t(PT\_WXTICKET)->addTicket($result\['ticket'\]); return $result\['ticket'\]; } else { $this->msg = "獲取js票據失敗"; return false; } } } // js sdk 票據簽名 當前網頁的URL,不包含#及其後面部分 public function jsSign($data) { // 1.所有待簽名參數按照字段名的ASCII 碼從小到大排序(字典序) ksort($data); // 2.URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串string1 採用原始值,不進行URL 轉義 $string1 = $this->ToUrlParams($data); // echo "string1:{$string1}"; // 3.對string1做sha1加密 $sign = sha1($string1); // echo "signature:{$sign}"; return $sign; } // 獲取訊息內容 public function getMsg() { return $this->msg; } /\*\* \* 格式化參數格式化成url參數 \*/ public function ToUrlParams($data) { $buff = ""; foreach ($data as $k => $v) { if ($k != "sign" && $v != "" && !is\_array($v)) { $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } } ?> // 微信登入 function wxlogin() { global $_G,$identifier,$config,$wx; if (!$_G[‘uid’]) { if ($_GET[‘state’]) { // 回調 $member = $wx->getUserInfo($_GET[‘code’]); if (!$member) { exit($wx->getMsg()); } if (!function_exists(“setloginstatus”)) { include_once libfile(‘function/member’); } // 設定登入狀態$wx setloginstatus($member, 2592000); checkfollowfeed(); $_G[‘uid’] = $member[‘uid’]; $_G[‘member’] = $member; } else { // 請求授權 對參數編碼 $redirect = urlencode(getProtocol() . $_SERVER[‘HTTP_HOST’] . $_SERVER[‘REQUEST_URI’]); $wx->getCode($redirect, ‘snsapi_base’); } } } function getProtocol() { return is_HTTPS() ? ‘https://’ : ‘http://’; } function is_HTTPS() { if ($_SERVER[‘HTTPS’] === 1 || $_SERVER[‘HTTPS’] === ‘on’ || $_SERVER[‘SERVER_PORT’] == 443) { return true; } return false; }

2019年4月5日 · 4 min · MoeJue

微信JSAPI支付

前陣子一直在做微信相關的業務,雖說不是什麼新技術,但之前一直沒有機會接觸到,然後踩了些坑,抽空整理記錄下。 微信支付一共分為7種,分別是:付款碼支付、JSAPI支付、Native支付、APP支付、H5支付、小程序支付、人臉支付。 此次業務中使用到的是微信JSAPI支付:用戶透過微信掃碼、關注公眾號等方式進入商家H5頁面,並在微信內呼叫 JSSDK完成支付 文件:https://pay.weixin.qq.com/wiki/doc/api/index.html SDK:[https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1 ](https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1)JSAPI支付需要在微信中的瀏覽器打開才能喚起微信支付,效果如下圖 附上介面程式碼 程式碼中使用了模板引擎 html: {$competition\['username'\]} {$prices\[0\]}鑽 {$prices\[1\]}鑽 {$prices\[2\]}鑽 {$prices\[3\]}鑽 {$prices\[4\]}鑽 註:1鑽=1元,1鑽={$activity\['offset'\]}票 立即微信支付 JavaScript: // 投票 var offset = {$activity[‘offset’]}; $(’#tips’).html(‘正在給{$competition[‘code’]}號贈送{$prices[0]}鑽=’+({$prices[0]}*offset)+‘票’); $(’#vote’).click(function(){ $.post(’/index/index/detailed.html?cid={$cid}&aid={$aid}’,{ formhash :’{FORMHASH}’, submit:‘1’, type:1, openid:’{$_G[‘member’][‘openid’]}’ },function(res){ alert(res.msg); if (res.code == 0) { $(’.box-1 span’).text(res.data.all); $(’.box-2 span’).text(res.data.rank); $(’.box-3 span’).text(res.data.up + ‘票’); } }); }) /* jQuery物件級別外掛程式擴展 */ $.fn.extend({ /* 單選框 */ hlRadio:function () { var radioEl=$(this); radioEl.click(function () { var price = 0; price = $(‘input:radio:checked’).val(); $(’#price’).val(’’); $(’#tips’).html(‘正在給{$competition[‘code’]}號贈送’+price+‘鑽=’+(price*offset)+‘票’); radioEl.siblings(“div”).removeClass(“active”); $(this).siblings(“div”).addClass(“active”); }); }, }); $(“input[name=‘price’]”).hlRadio(); $(’#price’).bind(‘input propertychange’, function(){ var price = 0; price = $(’#price’).val(); $(’#tips’).html(‘正在給{$competition[‘code’]}號贈送’+price+‘鑽=’+(price*offset)+‘票’); }) ...

2019年3月30日 · 4 min · MoeJue

國產邪神手辦開箱

「邪神」正是用於描述這些表情崩壞到離譜,細節不堪到令人髮指的手辦。 說起「邪神」,大家也許第一感覺就是「邪神四姐妹」,其實都是讓人膜拜的存在,四大邪神的威名萬世傳揚,不僅可以辟邪,而且擺出來非常長臉有沒有,殺人不見血的強大武器 在還沒下單時,我就已經想好了這次的標題《泳裝手辦果然棒》; 當看到這麼小的包裝的時候我已經預感到不好了,連箱子都才4個面 氣泡墊中若隱若現的身影 第一眼看去還好,但是不經細看 看一圈外包裝,沒什麼大毛病,標配 還好看得出來是楪祈 這。。。這角度,刁鑽 這手,無可挑剔 這泛白的頭髮 不過還句話說的好:物極必反。 當邪神邪到一定程度後,反而讓人欲罷不能…… 到貨後,我可能不得不修改標題了 國產最出名的邪神當屬「大邪神saber」,由於畫面可能引起不適,就不放圖片了 但邪神的影響力卻促使他們成為了真正的收藏品。 總之:「這是款治癒心靈,讓人心境平靜的產品。」

2019年3月14日 · 1 min · MoeJue

這次真的放鴿子了

完了完了,這次真的放鴿子了,前兩個月的年終總結還在誇自己去年每個月都有勤奮地發部落格,然而 flag 果然是用來打破的。 其實還不算太放鴿子(還有這樣算的嗎???黑人問號),今天其實是 2 月 29 日(強行挽回) 啦啦啦啦~~~ 好吧,其實放鴿子的原因主要還是因為工作繁忙,今晚也是好不容易沒有加班,才能寫寫部落格,平時白天上班就很累了,下班就想休息,根本沒那心思構思部落格了,得諒解得諒解。 要問我是什麼工作的話,IT 行業,現在是在某互聯網公司做程式設計師,全端工程師(笑),所以加班是常有的事,你懂的 所以所以以後有空的話可能會整理整理學習到的技術和心得分享分享(超乾的貨)。 但是新專案的話可能就沒時間去構思了 不過不用擔心部落客的頭髮問題,我們不一樣,我是面向 ACG 編程的,不會有髮際線問題 然後再說說部落格,其實從去年底就一直有想換主題的想法,看中了好幾款,但並不是 emlog 的主題,又沒辦法說換就換,現在的主題就是平平淡淡的規規矩矩的一個模板,有點審美疲勞了,也和我部落格的主題其實一點都不搭,但又怕花花綠綠的主題很多人不適應或者說是不喜歡,所以一直在糾結,要不要自己移植一份過來並保留現在的主題,允許用戶自行切換,但是呢。。。。。。。懶 差不多就這樣了,什麼事不能放到以後再說,主要還是水水文,逃~~

2019年3月1日 · 1 min · MoeJue