关于json编码解码的问题

其实json编码解码应该是一件很简单的事情,提供的类或库函数用起来也就是encode、decode,似乎不是一件很复杂的事情;但随着json的 使用的越来越多,还真就发现了一些不能不去注意的问题。

1.   含有自引用属性的类的encode和decode
       在js中, {"me":this} 是一个合法的对象,但是PHP对该对象做decode时,结果是: NULL
       在PHP中:
<?php
class test {
    public 
$a;
    
// 注意: 不能直接写为:
    // public $a = $this;
    
public function __construct() {
        
$this->$this;
    }
}
?>

test是一个合法的类,但是PHP对该对象做encode时,结果:
Warning: json_encode(): recursion detected in E:\home\desktop\test.php on line 26
{"a":{"a":null}}

2.  单引号的问题, key、value最好使用双引号来引
$obj json_decode('{"me":"this"}');  // 属性和值都是用双引号
var_dump($obj);

结果:
object(stdClass)#2 (1) {
  ["me"]=>
  string(4) "this"
}

$obj json_decode("{'a':'this'}");  // 属性和值都是用单引号
var_dump($obj);

结果: NULL

使用Services_JSON 倒是没有问题的
$json = new Services_JSON();
var_dump($json->decode("{'a':'this'}"));
exit;

输出:
object(stdClass)#2 (1) {
  ["a"]=>
  string(4) "this"
}

3.  特殊字符的转移问题
对于双引号、斜线、反斜线是需要转义的

今天重新了解了json这个东西,仔细解读了: http://json.org/  ,特别是里面的图的理解。

bat 脚本实例

1. for循环

循环数字:
@echo off
FOR /L %i IN (1,1,10) DO echo %i
#rem 输出 1 2 3 … 10

FOR %i IN (1,1,10) DO echo %i
#rem 输出 1 1 10


匹配当前目录下的所有文件(不包含子目录):
for %i in (*) do echo %i

匹配d:\ 目录下的js文件(遍历子目录):
for  /R d:\ %i in (*.js) do echo %i

循环目录(
不包含子目录),不包含文件:
for /D %i in (*) do echo %i

循环文件中的内容(按行分析):
for /F %i in (a.txt) do echo %i
#rem /F 说明set 是文件名

2.

登录解决方案

简单地说,登录就是输入用户名、密码,点击登录按钮就行了;但是到现在为止,我做登录已经两年了,如果真的这么简单,我这两年真就白活了;
其实,登录里面也有很多学问呢,做登录我们要考虑很多安全方面的问题,如:
一、防止扫密码
二、防止cookie被盗
三、防止密码被盗

每一个问题都很难做到像数学里描述一个逻辑那样的严谨,否则用户就必须符合很多条件才能上网了。

我们这里先讨论一下登录的问题,首先登录面临两个问题:
一、密码不能明文传输
二、登录使用的请求信息不能被截获,或者说即使被截获也不能使用

要解决这两个问题,下面给出几个解决方案:
一、使用https
登录

   优点: 只需要修改一下协议,就可以解决两个问题,做起来比较简单
   缺点:
         1. https 需要购买证书,是要花钱的,每年大概3000~10000不等
         2. 不是所有的客户端都只是https的
         3. 如果客户端的时间差的太多,也是无法访问https的
         4. 证书吊销列表的下载也影响登录的速度
         5. 浏览器对https有很多的安全限制,使得https和http之间的切换可能会有警告对话框
         6. 。。。

二、 使用login ticket的方式

   1. 提交用户名、密码之前先从服务器获取一个登录使用的票据lt,以lt为key存到mc里面吧
   2. 使用username=xxx&password=md5(password+lt)&lt=xxx 登录
   3. 根据lt查mc,如果存在,在根据username取password,做md5后比较;如果lt不存在,则该请求视为过期或重复请求

   优点:
      1. 不需要使用https
   缺点:
      1. 多一次请求
      2. 客户端需要做md5的代码,md5.js 压缩后也6k多了


三、 使用nonce的方式

   1. 使用username=xxx&password=md5(password+nonce)&nonce=yyyyy&timestamp=time_of_client_now 登录
   2. 服务器端的检查过程:
      if (timestamp + 5mins < server_time_now && md5(username+nonce) not in mc && 检查密码 && 将md5(username+nonce) 写入mc) 登录成功 else 登录失败
  
   优点:
      a. 一次请求就可以完成
      
   缺点:
      a. 对客户端的时间要求比较苛刻,不允许客户端时间比服务器快,不允许客户端比服务器时间慢超过5分钟

   该方式适用的情况: 客户端和服务器基本保证时钟同步


四、 该方式是二、三的结合

   1. 提交用户名、密码之前先获取一下服务器的时间timestamp
   2. 使用username=xxx&password_md5=md5(password+timestamp)&timestamp=time_of_server_now 登录
   3. 服务器端的检查过程同三、2.

  
优点:
1. 与二相比,第一次请求不需要写mc,实际登录成功之后才写mc

        


javascript 点滴

// eval 函数和new Function的上下文环境:
// eval()函数入口参数中指定的字符串总是被作为当前函数上下文中的语句来执行
// new Function() 中传入的字符串总是被作为一个全局的、匿名函数闭包中的语句行被执行
//  

eval("var a = 'global';");  // 声明一个全局的变量a
var obj = {};
(function (){

this.func = function() {
            eval("var a = 'internal';"); // 这里没有覆盖全局的变量a
            console.log("internal func:"+a); // 这里打印的a的值为 internal
            new Function("console.log('new Function:'+a);")();   // 这里打印的a的值为 global
            window.eval("alert(a);");  // 这里在IE和Firefox中表现不同,IE中认为是internal,Firefox中认为是global
    };

}).call(obj);

obj.func();
console.log("global:"+a);   // 这里打印的a的值为 global

// 使用eval获取对象直接量的方法,如:

var aobj = eval("{'a':'A','b':'B'}");  
这种写法是错误的,因为参数字符串没有被理解为一个对象,而是被理解为一个符合语句;然而作为一个符合语句,这里是有语法错误的,所以执行错误,正确的写法为:
var aobj = eval("({'a':'A','b':'B'})");

不过在jscript中存在一个例外:函数直接量(这里指匿名函数)不能通过这种方式来获得,例:

var func = eval('(function(){})');
alert(typeof func); // 输出为undefined

这种情况下,可以用具名函数来得到,例:
var func;
eval(
'function func(){}');

alert(typeof func); // 输出为 function

但是你可能遇到必须使用匿名函数的情况(不打算使用上例那样确定的函数名),这时就需要稍微复杂一些的代码(使用表达式运算),例:

// var func = eval('(function(){}).prototype.constructor');
// var func = eval('({$:function(){}}).$');
// var func = eval('[function(){}][0]');
...

javascript复制功能的实现

        

  1. /** 
  2.     

  3.  * 复制代码,支持IE/Firefox/NS 
  4.     

  5.  */  
  6.     

  7. function copyToClipboard(txt) {  
  8.     

  9.     if (window.clipboardData) {  
  10.     

  11.         window.clipboardData.clearData();  
  12.     

  13.         window.clipboardData.setData("Text", txt);  
  14.     

  15.     } else if (navigator.userAgent.indexOf("Opera") != -1) {  
  16.     

  17.         window.location = txt;  
  18.     

  19.     } else if (window.netscape) {  
  20.     

  21.         try {  
  22.     

  23.             netscape.security.PrivilegeManager  
  24.     

  25.                     .enablePrivilege("UniversalXPConnect");  
  26.     

  27.         } catch (e) {  
  28.     

  29.             alert("你使用的FireFox浏览器,复制功能被浏览器拒绝!\n请在浏览器地址栏输入“about:config”并回车。\n然后将“signed.applets.codebase_principal_support”双击,设置为“true”");  
  30.     

  31.             return;  
  32.     

  33.         }  
  34.     

  35.         var clip = Components.classes[‘@mozilla.org/widget/clipboard;1’]  
  36.     

  37.                 .createInstance(Components.interfaces.nsIClipboard);  
  38.     

  39.         if (!clip)  
  40.     

  41.             return;  
  42.     

  43.         var trans = Components.classes[‘@mozilla.org/widget/transferable;1’]  
  44.     

  45.                 .createInstance(Components.interfaces.nsITransferable);  
  46.     

  47.         if (!trans)  
  48.     

  49.             return;  
  50.     

  51.         trans.addDataFlavor(‘text/unicode’);  
  52.     

  53.         var str = new Object();  
  54.     

  55.         var len = new Object();  
  56.     

  57.         var str = Components.classes["@mozilla.org/supports-string;1"]  
  58.     

  59.                 .createInstance(Components.interfaces.nsISupportsString);  
  60.     

  61.         var copytext = txt;  
  62.     

  63.         str.data = copytext;  
  64.     

  65.         trans.setTransferData("text/unicode", str, copytext.length * 2);  
  66.     

  67.         var clipid = Components.interfaces.nsIClipboard;  
  68.     

  69.         if (!clip)  
  70.     

  71.             return false;  
  72.     

  73.         clip.setData(trans, null, clipid.kGlobalClipboard);  
  74.     

  75.     }  
  76.     


  77.     

javascript数组之奇怪用法

今天用到javascript的数组时,发现一个非常见的写法:

var arr = ['a','b','c'];
for (
i in arr) {
      
console.log("tag"+i);
      
console.log(arr.push(i));  // 期望: 我也不知道这将会输出什么
}
输出结果:

tag0
4
tag1
5
tag2
 6


var
arr = ['a','b','c'];
for (
i in arr) {
      
console.log(arr.pop());  // 期望: c b a
}

输出结果:

c
b

不知道怎么解释这种现象,基本应该是数组本身也有一个指针,for语句和pop、push操作都在同时使用该指针,于是结果就不像我们想象的那样了。

var arr = ['a','b','c'];
for (
i in arr) {
   
delete arr[i];  // 注意理解delete 的含义
}

console.log(arr);  // 期望: []

输出结果:
[undefined, undefined, undefined]

为何不能访问https

最近遇到一些用户不能访问https,下面记录一下不能访问https的几种情况:

1. 用户的电脑的时间不在证书有效期内

   a. 用户将电脑时间调到了证书生效时间以前,或证书确实还没有生效

   b. 用户将电脑时间调到了证书失效时间以后,或证书确实已经失效

2. 用户的浏览器不支持https,或没有开启https的相关选项;由于ssl2存在安全问题,所以浏览器一般默认启用ssl3 tls,而不启用ssl2
3. 浏览器存在bug,发现IE 8.0.6001.18702 如果不启用ssl2,访问https就有问题