顯示具有 javascript 標籤的文章。 顯示所有文章
顯示具有 javascript 標籤的文章。 顯示所有文章

2020年4月16日 星期四

Vue心得

安裝nodejs和npm

https://tecadmin.net/install-latest-nodejs-and-npm-on-centos/  How To Install Latest Nodejs on CentOS/RHEL 7

新增Node.js Yum Repository - Stable 版本(12.x)

# yum install -y gcc-c++ make
# curl -sL https://rpm.nodesource.com/setup_12.x | sudo -E bash -

安裝Node.js

# yum install nodejs

檢查 Node.js 和 NPM 版本

# node -v
v12.16.2
# npm -v
6.14.4

npm命令自動完成

$ npm completion >> ~/.bashrc
$ . ~/.bashrc


升級npm


npm i 就是npm install,只是簡寫
https://stackoverflow.com/questions/6237295/how-can-i-update-nodejs-and-npm-to-the-next-versions  How can I update NodeJS and NPM to the next versions?
# npm install -g npm

安裝/升級Vue Cli

https://cli.vuejs.org/zh/guide/installation.html
# npm install -g @vue/cli
...
-g : 同--global ,global模式安裝,將會安裝到 /usr/lib/node_modules/@vue/cli 下

檢查版本

# vue --version
@vue/cli 4.3.1

npm install的--save是什麼意思

https://stackoverflow.com/a/19578808  What is the --save option for npm install?
npm 5.0.0 後預設將modules裝在dependency,所以 --save 已經不再需要了。另外--save-dev將套件存在devDependencies、--save-optional將套件存在optionalDependencies


創建一個新項目

https://ithelp.ithome.com.tw/articles/10222966  Day28 vue.js - Vue cli 3.0 環境建置

$ vue create hello-world

手動選取要 preset (預先裝置) 的特性

? Please pick a preset:
  default (babel, eslint)
❯ Manually select features

選取要安裝的特性 (用space多選)

預設選了Babel、Linter / Formatter
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◉ Vuex
 ◉ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

Babel : JavaScript 編譯器、轉譯器。
Router : Vue 的路由器
Vuex vuex(vue的狀態管理模式)
CSS Pre-processors : CSS 前處理器(如:less、sass)
Linter / Formatter : 程式碼風格檢查和格式化(如:ESlint)

是否使用 Router 歷史記錄模式

? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) Y
history 模式,這種模式充分利用 -history.pushState API 來完成 URL 跳轉而無須重新加載頁面。

css預先處理器

? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys)
❯ Sass/SCSS (with dart-sass)
  Sass/SCSS (with node-sass)
  Less
  Stylus

https://stackoverflow.com/a/56422541  Vue CLI CSS pre-processor option: dart-sass VS node-sass?  
簡單說選 dart-sass而不是node-sass 的原因:官方推薦、比較快

ESLint 協助讓你寫的程式符合規範的輔助工具,區分嚴謹程度

? Pick a linter / formatter config:
  ESLint with error prevention only
  ESLint + Airbnb config
❯ ESLint + Standard config
  ESLint + Prettier

提示錯誤的時間點

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit

配置文件怎麼放

? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files
  In package.json

是否將上述配置儲存到 preset 的 default

? Save this as a preset for future projects? (y/N) N

運行專案項目(開發用)

$ cd hello-world
$ npm run serve

運營專案指定端口

https://cli.vuejs.org/zh/config/#devserver
新增 vue.config.js
所有 webpack-dev-server 的选项 都支持。 vue.config.js 加入:
module.exports = {
  devServer: {
    port: 8100
  }
}
s
然後就能以  http://192.168.1.x:8100/ 訪問專案(當然server 8100端口防火牆要記得開)

關閉ESLint

https://stackoverflow.com/questions/49121110/how-to-disable-eslint-on-vue-cli-3  How to disable eslint on vue-cli 3?
vue.config.js 新增
module.exports = {
    chainWebpack: config => {
        config.module.rules.delete('eslint');
    }
}
這樣 npm run serve 時就不會做 eslint 檢查
WebStorm => Settings => Languages & Frameworks => Javascript => Code Quality Tools => ESLint => 勾選 Disable ESLint

用vue-native-websocket做長連結

https://juejin.im/post/5dd4ebdff265da47c8603e02   9012年末,带你快速上手vue-native-websocket

使用Mint-ui

https://zhuanlan.zhihu.com/p/61403630  2019最受欢迎的前端7个UI框架
https://juejin.im/post/5d674d87e51d4561fa2ec0a6  基于Vue CLI3 搭建五脏俱全的移动端H5应用


安裝

$ npm i mint-ui

使用

src/views/Test.vue:
import Vue from 'vue'
import Mint from 'mint-ui'
import 'mint-ui/lib/style.css'

Vue.use(Mint)
Mint.Toast('提示信息2')
s

import Vue from 'vue'
import Toast from 'mint-ui/lib/toast'
import 'mint-ui/lib/toast/style.css'

Vue.component(Toast.name, Toast)
Toast('提示信息4')
s
或安裝 babel-plugin-component ,可自動加載css
$ npm i babel-plugin-component -D
然後修改 babel.config.js
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  "plugins": [
    ["component", {
      "libraryName": "mint-ui",
      "style": true
    }]
  ]
}

需重新 npm run serve ,就可以這樣使用
import Vue from 'vue'
import { Cell, Checklist, Toast } from 'mint-ui'

Vue.component(Toast.name, Toast)
Toast('提示信息3')
s

打包項目到dist目錄

$ npm run build

如果在Windows上報錯

'vue-cli-service' 不是内部或外部命令,也不是可运行的程序

原因

node_modules/ 是在 CentOS上npm install的,專案在Windows卻不能 npm run serve、build

解法

https://github.com/vuejs/vue-cli/issues/1119#issuecomment-382105533  vue-cli-service does not run in cmd.exe or Powershell
在Windows 上刪除 node_modules/ 後重新 npm install

使用Vant

因為 mint-ui 已經2年以上沒更新了,改用還有在更新的vant
https://youzan.github.io/vant/#/zh-CN/quickstart  快速上手
https://github.com/youzan/vant  youzan/vant

安裝Vant

$ npm i vant -S

檢查已安裝插件的版本

$ npm list vant
hello-world@0.1.0 C:\Users\user\WebstormProjects\hello-world
`-- vant@2.6.3

使用

diff --git a/src/views/About.vue b/src/views/About.vue
 <template>
   <div class="about">
     <h1>This is an about page</h1>
+    <van-button type="primary">主要按钮2</van-button>
   </div>
 </template>
+<script>
+import Vue from 'vue'
+import Button from 'vant/lib/button'
+import 'vant/lib/button/style'
+Vue.component(Button.name, Button)
+export default {
+}
+</script>

Vue.component(Button.name, Button) - 沒引入會報錯 [Vue warn]: Unknown custom element: <van-button> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
https://github.com/youzan/vant/issues/359#issuecomment-347491408  全局注册的组件在单文件中不识别 #359
chenjiahan: Vue.use 是注册插件用的,注册组件请使用 Vue.component
export default {} - 沒寫會報錯 TypeError: Cannot set property 'render' of undefined
https://stackoverflow.com/a/51021896  Cannot set property 'render' of undefined

自動引入style

安裝babel-plugin-import 插件
$ npm i babel-plugin-import -D

babel 7 在 babel.config.js 配置
diff --git a/babel.config.js b/babel.config.js
   plugins: [
     ['component', {
       libraryName: 'mint-ui',
       style: true
     }],
+    ['import', {
+      libraryName: 'vant',
+      libraryDirectory: 'es',
+      style: true
+    }, 'vant']
   ]
 }
一定要用 babel-plugin-import,用 babel-plugin-component 會報錯
Module not found: Error: Can't resolve 'vant/lib/toast/style.css' in

import Vue from 'vue'
import { Button } from 'vant'
Vue.component(Button.name, Button)
export default {
}
就是少寫import css那一行

ps. https://www.npmjs.com/package/@vue/cli-plugin-babel  @vue/cli-plugin-babel
@vue/cli-plugin-babel 使用 Babel 7

修正Cordova中字體文件路徑錯誤

環境: vant@2.6.3cordova@9.0.0
https://github.com/youzan/vant/issues/2366  file://协议下加载字体文件路径错误 #2366
https://stackoverflow.com/q/14575208  Using css font-face in a Phonegap Windows Phone 8 app

Tabbar 上的圖是用 vant-icon-db1de1.woff2 畫出來的,但在cordova中一樣因為 file:// 協議的關係,使得字型缺失
vant-icon-db1de1.woff2 是在 node_modules/vant/es/icon/index.css 的 @font-face 中請求 https://img.yzcdn.cn/vant/vant-icon-db1de1.woff2 來的

解法

將 vant-icon-db1de1.woff2 下載到本地  src/assets/vant-icon-db1de1.woff2 。 src/App.vue 加入( 從node_modules/vant/es/icon/index.css 的 @font-face 粘過來修改)
@font-face {
  font-weight: 400;
  font-family: vant-icon;
  font-style: normal;
  font-display: auto;
  src: url("assets/vant-icon-db1de1.woff2") format('woff2')
}
即可










2018年4月26日 星期四

解決JSON.stringify()報錯Converting circular structure to JSON

因為現在遇到一套程式一部分被js uglify過了。使用JSON.stringify()要看他的object全貌,報錯
JSON.stringify(gagame.Games.getCurrentGame().getCurrentGameMethod())
Uncaught TypeError: Converting circular structure to JSON
    at JSON.stringify (<anonymous>)
    at <anonymous>:1:6
解法:
使用 circular-json
將 circular-json.js  直接貼到console下就可以照下面方法用了
CircularJSON.stringify(gagame.Games.getCurrentGame().getCurrentGameMethod())
...// json string will show here
(然後複製貼到sublime後去美化JSON觀察這個object)



參考資料:
https://stackoverflow.com/questions/11616630/json-stringify-avoid-typeerror-converting-circular-structure-to-json/31817879#31817879  JSON.stringify, avoid TypeError: Converting circular structure to JSON
https://github.com/WebReflection/circular-json  CircularJSON




2017年7月27日 星期四

javascript 正則批配取內容(同PHP的 preg_match_all)

https://stackoverflow.com/questions/3291289/preg-match-in-javascript
使用()取出匹配的內容
ex.
var text = '||||||03';
var matches = text.match(/\|\|\|\|\|\|(\d{2})/);
console.log(matches[1]); // 03

b
(\d{2})
括號() 在這邊非常好用

2015年10月22日 星期四

PHP和javascript 的 hex、byte陣列、string轉換

某次使用SlowAES  函數cryptoHelpers.generateSharedKey(8)產生的iv經過base64加密後的結果如下
R1We4y0JRP5w06Z8tUBPAw==

先看 https://code.google.com/p/slowaes/source/browse/trunk/js/cryptoHelpers.js?r=33 的 generateSharedKey 怎麼產生的
generateSharedKey:function(len)
{
 if(len === null)
  len = 16;
 var key = [];
 for(var i = 0; i < len*2; i++)
  key.push(this.getRandom(0,255));
 return key;
}
產生長度為8*2 ,內容為 0-255 的 byte 陣列

使用 cryptoHelpers.js 對他做處理,觀察各個型態的內容
// need include cryptoHelpers.js
var base64 = 'R1We4y0JRP5w06Z8tUBPAw==';
console.log(cryptoHelpers.base64.decode(base64)); // base64 decode => byte array
console.log(cryptoHelpers.convertByteArrayToString(cryptoHelpers.base64.decode(base64))); // to string
console.log(cryptoHelpers.toHex(cryptoHelpers.base64.decode(base64))); // to hex

結果:
cryptoHelpers.base64.decode(base64):[71, 85, 158, 227, 45, 9, 68, 254, 112, 211, 166, 124, 181, 64, 79, 3]
cryptoHelpers.convertByteArrayToString(cryptoHelpers.base64.decode(base64)):GUžã- DþpÓ¦|µ@O
cryptoHelpers.toHex(cryptoHelpers.base64.decode(base64)):47559ee32d0944fe70d3a67cb5404f03

使用PHP處理
$iv = 'R1We4y0JRP5w06Z8tUBPAw==';

echo "
base64_decode(\$iv):".base64_decode($iv); // base64 decode => binary string

$iv64 = base64_decode($iv);
echo "
strlen(\$iv64):".strlen($iv64);  // 長度16
echo "
pack('H*', bin2hex(\$iv64)):".pack('H*', bin2hex($iv64)); // 與base64_decode($iv)結果相同
echo "
bin2hex(\$iv64):".bin2hex($iv64); // to hex

// to bytes array
for ($i=0; $i < strlen($iv64); $i++) { 
    $data[] = ord(substr($iv64,$i,1)); // 使用ord將字元轉成int
}
echo "
\$data:";
print_r($data);
echo "
";

結果:
base64_decode($iv):GU��- D�pӦ|�@O
strlen($iv64):16
pack('H*', bin2hex($iv64)):GU��- D�pӦ|�@O
bin2hex($iv64):47559ee32d0944fe70d3a67cb5404f03
$data:Array
(
    [0] => 71
    [1] => 85
    [2] => 158
    [3] => 227
    [4] => 45
    [5] => 9
    [6] => 68
    [7] => 254
    [8] => 112
    [9] => 211
    [10] => 166
    [11] => 124
    [12] => 181
    [13] => 64
    [14] => 79
    [15] => 3
)

還可以去 Unicode/UTF-8-character table 做字元最後的檢查
http://dev.networkerror.org/utf8/?start=0&end=255&cols=4&search=&show_uni_int=on&show_uni_hex=on&show_html_ent=on&show_raw_hex=on&show_raw_bin=on  0-255 的 Unicode Number (int) / Unicode Number (hex) / Char
http://www.scarfboy.com/coding/unicode-tool?s=000047  以hex 搜尋字元

參考資料:
http://stackoverflow.com/questions/11044802/php-hex-and-binary PHP Hex and Binary






2015年10月14日 星期三

AES 加密心得

前言:要跟java那邊用AES加密後的資料對接

在網路上找到許多不同語言的實作方式,但加密出來的結果都不一樣

原來是 AES encryption 有以下幾種mode

● ECB should not be used if encrypting more than one block of data with the same key.
當使用相同key加密一個block以上的資料時,ECB不應該被使用
● CBC, OFB and CFB are similar, however OFB/CFB is better because you only need encryption and not decryption, which can save code space.
CBC, OFB 和CFB類似。OFB/CFB比較好,因為你只需要加密不需要解密,以減少code的量
● CTR is used if you want good parallelization (ie. speed), instead of CBC/OFB/CFB.
當你想要好的平行處理(如:速度),使用CTR。而不是CBC/OFB/CFB。
The most important caveat with CTR mode is that you never, ever re-use the same counter value with the same key. If you do so, you have effectively given away your plaintext. ( http://stackoverflow.com/questions/4951468/ctr-mode-use-of-initial-vectoriv CTR mode use of Initial Vector(IV) )
最重要的是,你不要重複使用相同的key(IV,隨機產生),如果你這樣做,你已有效地給了你的明文
● XTS mode is the most common if you are encoding a random accessible data (like a hard disk or RAM).
XTS用在硬碟和RAM上
● OCB is by far the best mode, as it allows encryption and authentication in a single pass. However there are patents on it in USA.
OCB最好,因為他允許加密和認證在單通道。然而美國擁有其專利。( 所以意味著你在網路上找不到實作他的code )

你必須每次都用獨特的IV去加密,如果你不能保證他的隨機性,請用只需要隨機數(非IV)的OCB。固定的IV使得人們能不斷的猜測下一個,隨機數能避免這個風險

初始向量 Initialization vector (IV) 可被公開
http://ijecorp.blogspot.com/2013/08/python-m2crypto-aes-encrypt-decrypt.html
IV 本身並不需要保護,它是可以被公開的。而IV的最大長度必須是 16 bytes,而且產生IV的方式必須是無法預測的,也就是隨機產生即可。
http://stackoverflow.com/questions/8804574/aes-encryption-how-to-transport-iv
There is no security hole by sending the IV in clear text - this is similar to storing the salt for a hash in clear: As long as the attacker has no controll over the IV/salt, and as long as it is random, there is nor problem.
用明文傳送IV沒有安全的漏洞。這就像你做hash加了salt一樣,只要攻擊者無法掌握IV(salt)並且他是隨機的,就不會有問題。

使用php做AES CBC 128 pkcs5padding加密
$value = "张根";
$key = "Bar12345Bar12345"; //16 Character Key

echo strToHex('张根'); // hex: e5bca0e6a0b9

$encrypted = getEncrypt($value, $key);
echo "\n\$encrypted:".$encrypted;
echo "\n\getDecrypt(\$encrypted, \$key):".getDecrypt($encrypted, $key);

function pkcs5_pad ($text, $blocksize) { // https://github.com/stevenholder/PHP-Java-AES-Encrypt/blob/master/security.php
 $pad = $blocksize - (strlen($text) % $blocksize); 
 return $text . str_repeat(chr($pad), $pad); 
} 

function getEncrypt($sStr, $sKey) { // http://stackoverflow.com/questions/4537099/problem-with-aes-256-between-java-and-php
 global $iv;
 $sStr = pkcs5_pad($sStr, 16); // 這個16是 mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC) 的結果
 echo "\n\$sStr:".$sStr;  // 測試pkcs5 padding的結果
 // 產生$iv,如果用class寫,可以避免全域變數
 // $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND);
 // echo "\n\$iv:".$iv; // 這是隨機產生的內容
  return base64_encode( // 用bin2hex()亦可,但解密時要用hex2bin()
    mcrypt_encrypt(
        MCRYPT_RIJNDAEL_128, 
        $sKey,
        $sStr,
        MCRYPT_MODE_CBC,
        "ThisIsASecretKet" // $iv,測試時寫死
    )
  );
}

function getDecrypt($sStr, $sKey) {
 global $iv; // 要與 getEncrypt()產生的$iv一致,才能解出來
  return mcrypt_decrypt(
    MCRYPT_RIJNDAEL_128, 
    $sKey, 
    base64_decode($sStr), // 加密時用bin2hex(),則解密時要用hex2bin()
    MCRYPT_MODE_CBC,
    "ThisIsASecretKet"
  );
}

function strToHex($string) // http://ditio.net/2008/11/04/php-string-to-hex-and-hex-to-string-functions/
{
    $hex='';
    for ($i=0; $i < strlen($string); $i++)
    {
        $hex .= dechex(ord($string[$i]));
    }
    return $hex;
}

結果:
e5bca0e6a0b9 //這邊是utf8中文字轉hex的結果,如果其他地方字串轉hex不是這個代表他們的字串原本編碼不是utf-8
$sStr:张根 // pkcs5 padding的結果
$encrypted:LE/jvtjPWJk7qJc49Xl3eQ== // aes加密後 base64_decode()的結果
\getDecrypt($encrypted, $key):张根 // aes解密結果

說明:
因為java那邊只能用 128bit,所以只能選 MCRYPT_RIJNDAEL_128
$iv = Initial Vector(IV) 初始向量
在 https://github.com/stevenholder/PHP-Java-AES-Encrypt/blob/master/security.php 範例中,我們可以看到他加密不是用 mcrypt_encrypt 而是
public static function encrypt($input, $key) {
    $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
    $input = Security::pkcs5_pad($input, $size);
    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
    $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    mcrypt_generic_init($td, $key, $iv);
    $data = mcrypt_generic($td, $input);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    $data = base64_encode($data);
    return $data;
}
mcrypt_generic() => 低階API ,更有彈性
mcrypt_encrypt() => 高階工具( higher-level utility )
參考資料:
http://stackoverflow.com/questions/2773535/mcrypt-generic-vs-mcrypt-encrypt mcrypt_generic vs mcrypt_encrypt

http://php.net/manual/en/function.mcrypt-encrypt.php
string mcrypt_encrypt ( string $cipher , string $key , string $data , string $mode [, string $iv ] )
mode的格式是 MCRYPT_MODE_modename ,modename可使用"ecb", "cbc", "cfb", "ofb", "nofb" or "stream"
如: MCRYPT_MODE_ECB

因為mcrypt_encrypt() 出來的結果打印是二進位亂碼,所以都用 bin2hex()或base64_encode()去轉換一次

報錯:
Warning: mcrypt_encrypt(): Key of size 15 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported
如果你出現這個錯誤,請把$key補到16位(或24, 32位)
$key=$key."\0"; //缺幾位就補幾個


PHP範例參考資料:
https://github.com/stevenholder/PHP-Java-AES-Encrypt/blob/master/security.php 使用pkcs5_pad()方法
http://stackoverflow.com/questions/4537099/problem-with-aes-256-between-java-and-php  getEncrypt($sStr, $sKey)和getDecrypt($sStr, $sKey) 原型

使用Java做AES CBC 128 pkcs5padding加密
import java.io.UnsupportedEncodingException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class Encryptor {
    public static String encrypt(String key1, String key2, String value) {
        try {
            IvParameterSpec iv = new IvParameterSpec(key2.getBytes("UTF-8"));

            SecretKeySpec skeySpec = new SecretKeySpec(key1.getBytes("UTF-8"),
                    "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string:"
                    + Base64.encodeBase64String(encrypted));
            return Base64.encodeBase64String(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String key1, String key2, String encrypted) {
        try {
            IvParameterSpec iv = new IvParameterSpec(key2.getBytes("UTF-8"));

            SecretKeySpec skeySpec = new SecretKeySpec(key1.getBytes("UTF-8"),
                    "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        String key1 = "Bar12345Bar12345"; // 128 bit key
        String key2 = "ThisIsASecretKet";
        System.out.println(decrypt(key1, key2,
                encrypt(key1, key2, new String("张根".getBytes("utf-8")))));
        System.out.println(parseByte2HexStr("张根".getBytes("utf-8"))); // print "张根" utf-8 in hex
    }
    
    /**
     * 将16进制转换为二进制
     * 
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /**
     * 将二进制转换成16进制
     * 
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toLowerCase());
        }
        return sb.toString();
    }
}

結果:
encrypted string:LE/jvtjPWJk7qJc49Xl3eQ== // aes加密後 base64_decode()的結果,需與php結果一致
张根 // aes 解密結果
e5bca0e6a0b9 // "张根"utf8轉hex的結果

說明:
parseHexStr2Byte(String hexStr) 和 parseByte2HexStr(byte buf[]) 這兩個function在這邊純粹測試用,與加解密無關。可忽略
我遇到的最大難點之一就是,java和php 英文字加密出來結果一樣,但是中文加密結果不一樣。( 這邊23樓也遇到一樣問題: http://my.oschina.net/Jacker/blog/86383?p=3#comments  )
原因是java在加密前的中文編碼有問題。先用
System.out.println(parseByte2HexStr("张根".getBytes("utf-8")));
檢測hex是否相同
加密時在外面就轉成utf-8再加密
encrypt(key1, key2, new String("张根".getBytes("utf-8"))) 

如果你的cipher(密文),想要用No Padding,如
Cipher cipher = Cipher.getInstance("AES/CBC/NoPADDING");
這樣你要加密的明文( "张根" ) 必須改成16位的字,否則java會報錯
encrypt(key1, key2, new String("123456789012345".getBytes("utf-8"))) // 必須改成16位字串,如1234567890123456
報錯:
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes

雖然php不做padding可以加密,但結果不一樣。為了配合java這邊,php那邊還是要做pkcs5 padding

原因:
java文件檔的編碼不是utf-8
解法:
eclipse => "左邊導航欄"你的"專案"上點右鍵 => Properties => Resource => Text file encoding 選
Other: UTF-8 ( 不要選Inherited from container (GBK) ) => OK ( 這樣你原本GBK的文件中文內容會變成亂碼,代表原本編碼錯誤 )


JAVA範例參考資料:
http://stackoverflow.com/questions/15554296/simple-java-aes-encrypt-decrypt-example Simple java AES encrypt/decrypt example

使用javascript ( SlowAES )做AES CBC 128 pkcs5padding加密
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="description" content="aes">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>aes</title>
        <script src="/jquery-1.10.2.min.js"></script>
        <script src="../js/aes.js"></script>
        <script src="../js/cryptoHelpers.js"></script>
        <script src="../js/jsHash.js"></script>
    </head>
    <body>
        <div id="output"></div>
        <script type="text/javascript">
        /**
        * An encryption setup to match our server-side one; see there for
        * documentation on it.
        **/
        function decrypt(input, key){
            var originalSize = 6;
            // var iv = 'R1We4y0JRP5w06Z8tUBPAw==';
            // iv = cryptoHelpers.base64.decode(iv); // 解密時需把base64加密後的iv解密成byte array
            var iv = "ThisIsASecretKet";
            iv = cryptoHelpers.convertStringToByteArray(iv);
            var cipherIn = input;
            // Set up encryption parameters
            var keyAsNumbers = cryptoHelpers.toNumbers( bin2hex( key ) );
            cipherIn = cryptoHelpers.base64.decode(cipherIn);
            var decrypted = slowAES.decrypt(
                cipherIn,
                slowAES.modeOfOperation.CBC,
                keyAsNumbers,
                iv
            );
            return cryptoHelpers.decode_utf8(cryptoHelpers.convertByteArrayToString(decrypted));
        }
        function encrypt( plaintext, key ){
            // Set up encryption parameters
            plaintext = cryptoHelpers.encode_utf8(plaintext);
            var inputData = cryptoHelpers.convertStringToByteArray(plaintext);
            var keyAsNumber = cryptoHelpers.toNumbers(bin2hex(key));
            var iv = cryptoHelpers.generateSharedKey(8); // 假設自動生成的iv做base64 encode加密後的結果是 R1We4y0JRP5w06Z8tUBPAw==
            var iv = "ThisIsASecretKet";
            iv = cryptoHelpers.convertStringToByteArray(iv);
            var encrypted = slowAES.encrypt(
                inputData,
                slowAES.modeOfOperation.CBC,
                keyAsNumber,
                iv
            );
            return cryptoHelpers.base64.encode(encrypted);
        }
        // Equivilent to PHP bin2hex
        function bin2hex (s) {
            var i, f = 0,
                a = [];
            s += '';
            f = s.length;
            for (i = 0; i < f; i++) {
                a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/, "0$1");
            }
            return a.join('');
        }
        // Equivilent to PHP hex2bin
        function hex2bin(hex) {
            var str = '';
            for (var i = 0; i < hex.length; i += 2)
                str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
            return str;
        }
        /**
        * Some simple testing code
        **/
        $(function(){
            var key = "Bar12345Bar12345"; // key
            var plaintext = "张根";
            var output = "";
            var cipherText = encrypt(plaintext,key);
            var newPlaintext = decrypt(cipherText,key);
            output += ("<br>plaintext=" + plaintext);
            output += ("<br>cipherText=" + cipherText);
            output += ("<br>newPlaintext=" + newPlaintext);
            $('#output').html(output);
        });
        </script>
    </body>
</html>
結果:
plaintext=张根
cipherText=LE/jvtjPWJk7qJc49Xl3eQ==
newPlaintext=张根

如果要傳做過base64加密後的iv給php端,php端的iv要這樣設定,才能解密
$aes->set_iv(base64_decode($iv));

SlowAES的aes.js、cryptoHelpers.js、jsHash.js
https://code.google.com/p/slowaes/source/browse/trunk/js/

加密出來的結果要傳送
POST
1. 塞入表單後submit POST
GET
1. 塞入表單後submit GET
2. 組URL
url = $('#action').val()+"&aes_encrypt="+encodeURIComponent($('#reqParam').val())+"&iv="+$('#iv').val();
location.href = url;
必須用在字段上使用 encodeURIComponent 。
1. 勿組出url後再encodeURIComponent(url), 因為http:// 也會被encode
2. 使用encodeURI無效


其他java或php實作AES範例:
http://www.movable-type.co.uk/scripts/aes-php.html  Aes Ctr <PHP>
http://www.movable-type.co.uk/scripts/aes.html Aes Ctr <javascript> => github: https://github.com/chrisveness/crypto
http://aesencryption.net/ AES encryption <PHP/JAVA> =>Java驗證未過,可能是當初測時編碼問題
https://code.google.com/p/crypto-js/#AES crypto-js<javascript>
http://point-at-infinity.org/jsaes/ jsaes: AES in JavaScript <javascript>
http://www.cnblogs.com/yipu/articles/3871576.html [转]php与java通用AES加密解密算法 (最初對接成功的範例,但有java中文編碼問題) <PHP/JAVA>
https://github.com/stevenholder/PHP-Java-AES-Encrypt  PHP-Java-AES-Encrypt<PHP/JAVA>
http://www.java2s.com/Code/Java/Security/BasicIOexamplewithCTRusingAES.htm Basic IO example with CTR using AES : File Secure IO « Security « Java <JAVA>
http://magiclen.org/aes/ 在Java、Android、PHP實現AES加解密,並且互通的方式 <PHP/JAVA>

參考資料:
https://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86 高階加密標準
http://stackoverflow.com/questions/1220751/how-to-choose-an-aes-encryption-mode-cbc-ecb-ctr-ocb-cfb  How to choose an AES encryption mode (CBC ECB CTR OCB CFB)?







2014年12月19日 星期五

javascript去檢測(類似ping)區網有無這個ip

http://stackoverflow.com/questions/4282151/is-it-possible-to-ping-a-server-from-javascript
修改後:
ping = function(ip, callback) {
 if (!this.inUse) {
  this.status = 'unchecked';
  this.inUse = true;
  this.callback = callback;
  this.ip = ip;
  var _that = this;
  this.img = new Image();
  this.img.onload = function() {
   _that.inUse = false;
   _that.callback('responded');

  };
  this.img.onerror = function(e) {
   if (_that.inUse) {
    _that.inUse = false;
    _that.callback('responded', e);
   }

  };
  this.start = new Date().getTime();
  this.img.src = "http://" + ip;
  this.timer = setTimeout(function() {
   if (_that.inUse) {
    _that.inUse = false;
    _that.callback('timeout');
   }
  }, 1500);
 }
};

//使用:
new ping('192.168.0.88', function(status, e) {
 console.log(status);
});

有這個ip,在控制台會顯示 responded,沒有則會顯示timeout

2013年10月25日 星期五

防止img被選擇

議題:在likebox中連點右邊按鈕後會把中間的img選起來,如何不讓他選起來

解法:
firefox要用css
-moz-user-select:none;
其他用onselectstart="return false"

用js一次解法:
Obj.style.MozUserSelect = 'none';
Obj.unselectable = 'on'; // for IE5.5 http://www.tohoho-web.com/html/attr/unselectable.htm
Obj.onselectstart = function() { return false; };
Obj.onmousedown  = function() { return false; };

http://stackoverflow.com/questions/2700000/how-to-disable-text-selection-using-jquery
$(el).attr('unselectable','on')
     .css({'-moz-user-select':'-moz-none',
           '-moz-user-select':'none',
           '-o-user-select':'none',
           '-khtml-user-select':'none', /* you could also put this in a class */
           '-webkit-user-select':'none',/* and add the CSS class here instead */
           '-ms-user-select':'none',
           'user-select':'none'
     }).bind('selectstart', function(){ return false; });

Firefox(部份,不確定什麼原因,似乎非firefox版本問題,我當時版本24,做不出來)在likebox(mask之上)按鈕顏色會異常(移動或縮放瀏覽器後更可明顯觀察)



原因:
box-shadow在作怪
http://stackoverflow.com/questions/5095253/box-shadow-in-firefox
解法:
.fubar {
    box-shadow: 10px 10px 30px #000;
    -moz-box-shadow:none !important; /* 在firefox24中-moz-box-shadow屬性無反應 */
}

@-moz-document url-prefix() {
    .fubar {
        box-shadow:none; /* 採用 */
    }
}

2013年9月4日 星期三

javascript 行尾是否要加分號

http://darknuminous.pixnet.net/blog/post/27620166-javascript%E7%9A%84%E5%88%86%E8%99%9F%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A0%85
斷行JavaScript會多幫你加一分號
所以下面的這句:
return
true;
等同於
return;
true;
這會造成大錯誤,切記不要隨便斷行。

http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascript
下面這情況會出錯
// define a function
var fn = function () {
    //...
} // semicolon missing at this line

// then execute some code inside a closure
(function () {
    //...
})();

http://stackoverflow.com/questions/1482999/utility-to-auto-insert-semicolons-in-javascript-source-code
文內推薦使用 http://www.jslint.com/ 去優化js

http://stackoverflow.com/questions/13572602/how-to-upgrade-jslint-in-aptana
在aptana (3以後) 直接使用jslint
1. 視窗 -> 偏好設定 -> Aptana Studio -> Validation

視窗 -> 偏好設定 -> 直接搜尋Validation
2. 勾選Build和Reconcile (不確定哪個所以兩個都勾)
3. 開啟問題視圖(但因為專案下有太多檔案之前沒照jslint規則走和內含樣板符號,所以會列出很多錯誤,所以還是關掉了)

ps. 匿名函數的三種寫法:
http://dancewithnet.com/2008/05/07/javascript-anonymous-function/
1. 函数字面量:首先声明一个函数对象,然后执行它。
(function(){
  alert(1);
} ) ( );
2. 优先表达式:由于Javascript执行表达式是从圆括号里面到外面,所以可以用圆括号强制执行声明的函数。
( function(){
  alert(2);
} ( ) );
3. Void操作符:用void操作符去执行一个没有用圆括号包围的一个单独操作数。
void function(){
  alert(3);
}()
在console中下面代碼會出錯
(function() {
  console.log("test2");
})()
(function() {
  console.log("test1");
}())
test2
test1
但是把test1放到前面,只會出現test1就出錯了

ps.
使用jslint後遇到的問題,如何通過jslint驗證:
http://stackoverflow.com/questions/4979252/jslint-error-move-the-invocation-into-the-parens-that-contain-the-function
message: "Move the invocation into the parens that contain the function"
To pass JSLint's criteria, it needs to be written like this:
}(jQuery));
Though I think that particular criteria is a bit subjective. Both ways seem fine in my opinion.
(function () {})() makes a bit more sense to me since you wrap the full function, then call it
(function () {}()) looks like you're wrapping the result of the function call in a parens ...
- 結論 - 第一種方法雖然不會過,但是比較有sense

The “unexpected ++” error in jslint
http://stackoverflow.com/questions/3000276/the-unexpected-error-in-jslint
just do i += 1

"use strict";
http://stackoverflow.com/questions/1335851/what-does-use-strict-do-in-javascript-and-what-is-the-reasoning-behind-it
http://peihsinsu.blogspot.tw/2012/04/javascript-use-strict.html
use strict是ECMA-262 Edition 5定義的新語法,表示要用嚴格的Javascript語法來執行,有一些過去慣用的寫法就會出錯,例如使用變數前沒有用var宣告。
use strict主要是影響他所在的scope,如果在函數中使用,並不會讓global scope以及其他未使用的函數變成use strict。

2013年8月27日 星期二

javascript 操作XML失敗

西低-一似三伍二

目標:
將string_to_xml解出來的XML的某些node塞到新產生的的XML裡面去
然後再將新的XML透過XSLT轉成畫面

試過的方法:
xml 轉json ( 但是在 <![CDATA[ 包覆的內容無法正常轉出來 )
http://davidwalsh.name/convert-xml-json

json 轉 xml(沒有使用)
https://code.google.com/p/x2js/

產出的json格式string無法eval成object
http://goessner.net/download/prj/jsonxml/

IE無法使用innerHTML抓XML內容,新的node內容需要被重複使用無法用appendChild做
http://stackoverflow.com/questions/4630611/how-to-get-the-innerhtml-of-a-xml-document-ajax
http://stackoverflow.com/questions/6170911/does-innerhtml-work-with-xml-elements (IE不支援XMLSerializer)

只能移動node,無法複製node
http://stackoverflow.com/questions/954725/copying-one-dom-xml-node-to-another-in-javascript
http://stackoverflow.com/questions/3066427/copy-all-childnodes-to-an-other-element-in-javascript-native-way

This is more of a guess as I don't know offhand what .parseXml does but IE needs createElement for unknown node names. Can you try document.createElement('BadBrowsers') for every new node you are going to manipulate? - IE只能用createElement新增XML的node
http://stackoverflow.com/questions/5073953/can-ie-manipulate-xml-using-jquery

IE $(newNode).appendTo($xml.find("node2")); 和 $xml.find("node2").get(0).appendChild(newNode); 都跑不動
http://forum.jquery.com/topic/jquery-1-6-1-add-a-new-node-in-xml-16-6-2011

w3school的方法(各瀏覽器相容)
http://www.w3schools.com/dom/dom_nodes_add.asp
http://www.w3schools.com/dom/dom_nodes_create.asp.
http://www.w3schools.com/dom/dom_nodes_clone.asp - 複製同一個XML的node,需求為複製不同XML的node

除錯注意事項:
1. 在用append時要先用clone複製出node,不然append後該node會消失
2. XML要這樣寫才能在firebug(IE不行)觀察結構 xml.documentElement,對該XML操作新增節點後,有時候要再觀察其他XML再切回來,原XML修改後的結果才會出現

瓶頸:
IE不支援我js生成的XML

解法:
最後全解成html再用jquery做
my_dom = $("#content").clone()
$("#content").html('')
for (var i = 0; i < 5; i ++){
  $("#content").append(my_dom.find(".cell:eq("+i+")").clone());
}`

插曲:
在測IE7時發現IE7不支援display: inline-block
http://stackoverflow.com/questions/6544852/ie7-does-not-understand-display-inline-block
The IE7 display: inline-block; hack is as follows:(未測試)
display: inline-block;
*display: inline;
zoom: 1;
可使用 Conditional comments解
http://www.quirksmode.org/css/condcom.html

<p class="accent">
<!--[if IE]>
According to the conditional comment this is IE<br />
<![endif]-->
<!--[if IE 6]>
According to the conditional comment this is IE 6<br />
<![endif]-->
<!--[if IE 7]>
According to the conditional comment this is IE 7<br />
<![endif]-->
<!--[if IE 8]>
According to the conditional comment this is IE 8<br />
<![endif]-->
<!--[if IE 9]>
According to the conditional comment this is IE 9<br />
<![endif]-->
<!--[if gte IE 8]>
According to the conditional comment this is IE 8 or higher<br />
<![endif]-->
<!--[if lt IE 9]>
According to the conditional comment this is IE lower than 9<br />
<![endif]-->
<!--[if lte IE 7]>
According to the conditional comment this is IE lower or equal to 7<br />
<![endif]-->
<!--[if gt IE 6]>
According to the conditional comment this is IE greater than 6<br />
<![endif]-->
<!--[if !IE]> -->
According to the conditional comment this is not IE<br />
<!-- <![endif]-->
</p>

http://stackoverflow.com/questions/9892616/jquery-switching-application-from-live-to-on-method/9892671#9892671
http://blog.timc.idv.tw/posts/deprecation-of-jquery-live-function/
使用下面語法做到jquery 的live效果( jquery live在新版底層是用on做 )
// 舊
$('#myid').bind(event, fn);
// 新 (改名字就好)
$('#myid').on(event, fn);

// 舊
$('#not_in_dom_yet').live(event, fn)
// 新
$(document).on(event, '#not_in_dom_yet', fn);


1. live() 的原理是把事件綁在上層的元素,事件 bubble 上去之後再去檢查從下面上來的事件是不是符合之前設定的 selector。這個原理在 on()(或是 delegate())才會被暴露出來(有發現那個 document 嗎?)。如果只寫 live() 的話等於是不求甚解的用法,最明顯的問題是無法掌握事件觸發的順序,常常在 bind() 裡面有用的 ev.stopPropagation() 改成 live() 就沒用了。
2. live() 把事件掛在 document,雖然比每個元素都 bind() 有效率,但是還是要過濾很多傳上來的無關事件。用 delegate() 或是 on() 才能指定要把事件 bind 在哪裡。
3. live() 的語法不合邏輯。一個用 $('#not_in_dom_yet') 選元素的 jQuery 物件,裡面明明就沒有 DOM 元素,那照理說後面接上的方法都不應該做任何事情。結果 live() 反而是這樣運作的。

http://www.fileformat.info/info/unicode/char/200b/index.htm
&#8203; 在unicode中是空的字元 'ZERO WIDTH SPACE'

在FF中,使用
var xml = "<response></response>";
var $xml = $j($j.parseXML(xml));
產生出來的XML可以用 $xml[0] 去抓真實的XML DOM,使用$xml[0].documentElement 在firebug中觀察

直接在console上重寫
self.xxx_template = string_to_xml('xslt_str'); 的內容,而不用重新publish

使用perl將xml和xslt(去讀取放在主機上xslt格式的檔案)產生html
http://search.cpan.org/~shlomif/XML-LibXSLT-1.81/LibXSLT.pm









2013年1月15日 星期二

javascript 算個時間的差距

1. 先轉成timestamp

http://stackoverflow.com/questions/9873197/convert-date-to-timestamp-in-javascript
http://stackoverflow.com/questions/1968167/difference-between-dates-in-javascript

ex.

var confirm_date = "2012-01-15 12:34:56";
confirm_date = confirm_date.split(" ");
var [year,month,day] = confirm_date[0].split("-");
var confirm_timestamp = new Date(year,month,day).getTime();

2. 再相減 timestamp後除以你要比的時間單位(天,小時,分,秒)
http://stackoverflow.com/questions/1787939/check-time-difference-in-javascript
http://blogs.digitss.com/javascript/calculate-datetime-difference-simple-javascript-code-snippet/
ex.
var days_difference = Math.floor((now_timestamp - confirm_timestamp)/1000/60/60/24);








2012年11月22日 星期四

javascript 操作cookie

JavaScript bookmarklet to delete all cookies within a given domain
http://stackoverflow.com/questions/178263/javascript-bookmarklet-to-delete-all-cookies-within-a-given-domain
Clearing all cookies with JavaScript
http://stackoverflow.com/questions/179355/clearing-all-cookies-with-javascript

function deleteAllCookies() {
    var cookies = document.cookie.split(";");

    for (var i = 0; i < cookies.length; i++) {
     var cookie = cookies[i];
     var eqPos = cookie.indexOf("=");
     var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
     document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
    }
}


Get URL parameter with jQuery (用純js取get值)
http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
function getURLParameter(name) {
    return decodeURI(
        (RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
    );
}
JavaScript删除登录用户的所有的cookie信息的 (採用)
http://www.ityoudao.com/Web/Html_JS_646_1190.html
AJAX動態內容支援回上頁-HTML5篇
http://blog.darkthread.net/post-2011-09-23-ajax-history-in-html5.aspx
使用History ,但IE8,7,6不支援,所以ivan另裝套件讓ie支援History

2012年7月9日 星期一

javascript 物件寫法

需產生物件後才能使用物件和其方法。
出錯:
  
var obj = {  //少var 亦會出錯
  a : {
    a : function(){
    
    } ,
    
    b : (function(){
      console.log( obj ); // 出錯
    })()
  },
  b : (function(){
    console.log( obj ); // 出錯
  })()
}
  

正常:
var obj = {}

obj.a = {

  a : '123' ,
  b : '456' ,

  c : function(){
    return this.a + this.b ;
  } ,

  init : function(){

    console.log( this ) ;
  }

}

obj.a.init() ;
出錯:

var obj = {  //少var 亦會出錯
  a : {
      a : function(){
   
      } ,
   
      b : (function(){
   
        console.log( obj )
      })()
  },

  b : (function(){

    console.log( obj ) // 出錯
  })()
}

正常:



var obj = {}

obj.a = {

  a : '123' ,
  b : '456' ,

  c : function(){
    return this.a + this.b ;
  } ,

  init : function(){

    console.log( this ) ;
  }

}

obj.a.init() ;

http://stackoverflow.com/questions/3455405/how-to-remove-a-key-from-a-javascript-object
刪除一個物件的key
delete thisIsObject[key];