分类 PHP 下的文章

验证是否第一次登陆:

cookie 中的 deviceid

初始化,连接服务器后,发送:

{
    "lwp": "/reg",
    "headers": {
        "cache-header": "token app-key did ua vhost wv",
        "vhost": "WK",
        "ua": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 OS(windows/6.1) Browser(chrome/63.0.3239.132) DingWeb/3.6.0 LANG/zh_CN",
        "app-key": "85A09F60A599F5E1867EAB915A8BB07F",
        "wv": "im:3,au:3,sy:4",
        "did": "117851a2126f40aaa2f1a3e2df7c00dc",
        "mid": "804b0002 0"
    },
    "body": null
}
  • 主要字段的数据来源(JS实现):
  1. cache-header: 固定
  2. vhost:固定
  3. ua: 当前浏览器的 navigator.userAgent
  4. app-key:固定为 85A09F60A599F5E1867EAB915A8BB07F
  5. wv: 固定
  6. did: cookie 没有 deviceid 时,由客户端生成,详见下面的 getDid(uuid.v4标准);否则不传该字段,但连接 WebSocketHTTP 请求头应该有包含 Cookie:deviceid=7fc0930dba774fcfa7e1d7aac56fabcd; deviceid_exist=true;
  7. mid: genMid() + " 0"
  • 涉及到的代码段:
var i = 0
  , r = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];

function genMid() {
    var e = Math.floor(Math.random() * Math.pow(2, 16))
      , t = i++
      , n = "";
    return n += r[e >> 12 & 15],
    n += r[e >> 8 & 15],
    n += r[e >> 4 & 15],
    n += r[15 & e],
    n += r[t >> 12 & 15],
    n += r[t >> 8 & 15],
    n += r[t >> 4 & 15],
    n += r[15 & t]
};

function uuid_v4 () {
    var o = [], i = [], l = {};
    for (var e, t = 0; t < 16; t++)
        0 === (3 & t) && (e = 4294967296 * Math.random()),
            o[t] = e >>> ((3 & t) << 3) & 255;

    for (var u = 0; u < 256; u++)
        i[u] = (u + 256).toString(16).substr(1)


    var n = 0;
    return i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]] +
        "-" + i[o[n++]] + i[o[n++]] + "-" + i[o[n++]] + i[o[n++]] + "-" + i[o[n++]] + i[o[n++]] + "-" +
        i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]] + i[o[n++]]
}

function getDid () {
    return uuid_v4().replace(/\-/g, "");
}
对应PHP代码:
function getMid () {
    static $i = 0;

    $r = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];

    $e = rand(1, 65535);
    $i++;

    return $r[$e >> 12 & 15] .
           $r[$e >> 8 & 15] .
           $r[$e >> 4 & 15] .
           $r[15 & $e] .
           $r[$i >> 12 & 15] .
           $r[$i >> 8 & 15] .
           $r[$i >> 4 & 15] .
           $r[15 & $i];
}

function uuid_v4() {
    return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',

      // 32 bits for "time_low"
      mt_rand(0, 0xffff), mt_rand(0, 0xffff),

      // 16 bits for "time_mid"
      mt_rand(0, 0xffff),

      // 16 bits for "time_hi_and_version",
      // four most significant bits holds version number 4
      mt_rand(0, 0x0fff) | 0x4000,

      // 16 bits, 8 bits for "clk_seq_hi_res",
      // 8 bits for "clk_seq_low",
      // two most significant bits holds zero and one for variant DCE1.1
      mt_rand(0, 0x3fff) | 0x8000,

      // 48 bits for "node"
      mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
    );
}

function getDid () {
    return str_replace('-', '', uuid_v4());
}

服务器响应注册消息:

{
    "headers": {
        "mid": "804b0002 0",
        "sid": "ac1d503a5a55bf1454bb2724ef29f2f5882550192a20"
    },
    "code": 200
}

输入密码登陆:

{
    "lwp": "/r/Adaptor/LoginI/login",
    "headers": {
        "mid": "2634000f 0"
    },
    "body": [
        {
            "title": "Windows 7 Web", // 最长 20 字节
            "model": "Windows 7",
            "token": "C1515568916640551275078381515568916640194"
        },
        "+86-13900000000", // 登陆手机号
        "这是明文密码",
        "85A09F60A599F5E1867EAB915A8BB07F", // app-key
        null
    ]
}

服务器响应登陆成功的消息:

{
    "headers": {
        "dt": "j",
        "mid": "2634000f 0",
        "sid": "ac1d503a5a55bf1454bb2724ef29f2f5882550192a20"
    },
    "code": 400,
    "body": {
        "reason": "你在新的设备登录钉钉,为了保障你的账户安全,需要使用短信验证码确认",
        "code": "14001"
    }
}

客户端要求发送验证码:

{
    "lwp": "/r/Adaptor/LoginI/sendSmsCode",
    "headers": {
        "mid": "691e0010 0"
    },
    "body": [
        "+86-13900000000" // 登陆手机号
    ]
}

输入验证码:

{
    "lwp": "/r/Adaptor/LoginI/tokenLogin",
    "headers": {
        "mid": "b75d0023 0"
    },
    "body": [
        {
            "title": "Windows 7 Web",
            "model": "Windows 7",
            "token": "C1515568916640551275055381515568916640194"
        },
        "+86-13900000000", // 登陆手机号
        "1111", // 短信验证码
        "85A09F60A599F5E1867EAB915A8BB07F", //app-key
        "0",
        null
    ]
}

用户登陆成功,服务器响应:

{
    "headers": {
        "dt": "j",
        "mid": "b75d0023 0",
        "sid": "ac1d503a5a55bf1454bb2724ef29f2f5882550192a20"
    },
    "code": 200,
    "body": {
        "nickPinyin": "qi",
        "syncProtocol": false,
        "tokenId": "B:45cde49ed06c55fc758fbe1b4a7e7777",
        "openId": 33606666,
        "secretToken": "8reAacn5g=",
        "accessToken": "Gs/Go7jpo=",
        "expiredTime": 1516865322664,
        "nick": "昵称",
        "domain": "dingding",
        "tmpCode": "33405583_E755ADF8-E5A3-42DA-A60C-5555FCFE30B7",
        "appKey": "85A09F60A599F5E1867EAB915A8BB07F",
        "timestamp": "16124915505A584255406478",
        "userProfileExtensionModel": {}, 
        "refreshToken": "c2/kt52S8pvemA=="
    }
}

使用上一步得到的 body.tmpCode 请求服务器设置 cookie

GET https://static.dingtalk.com/media/setCookie?code=33405583_E755ADF8-E5A3-42DA-A60C-5555FCFE30B7&callback=__jp0

订阅消息

{
    "lwp": "/subscribe",
    "headers": {
        "token": "Gs/Go7jpo=", // 登陆成功后服务器推送消息中的 body.accessToken
        "sync": "0,0;0;0;",
        "set-ver": "0",
        "mid": "ab030024 0"
    }
}

服务端响应订阅:

{
    "headers": {
        "reg-sid": "ac1d503a5a55bf1454bb2724efdfdfdfdf5882550192a20",
        "reg-uid": "33400003@dingding",
        "mid": "ab030024 0",
        "uuid": "ggHaACRjNjc2ZmQ3jU5LTQ0MTEtOGQwMS02YWRjYODMCsTMzNDA2NjgzQGRpbmdkaW5n",
        "real-ip": "61.139.59.61",
        "sid": "ac1d503a5a55bf1454bb2724ef29f2f5882550192a20"
    },
    "code": 200
}

获取状态

{
    "lwp": "/r/Sync/getState",
    "headers": {
        "mid": "e4d10004 0"
    },
    "body": [
        {
            "pts": 0,
            "highPts": 0,
            "seq": 0,
            "timestamp": 0,
            "tooLong2Tag": ""
        }
    ]
}

服务端响应获取的状态结果:

{
    "headers": {
        "dt": "j",
        "mid": "e4d10004 0", // 和上面获取状态时发送的 mid 一样,表明是响应的数据
        "sid": "0b8319955a57146440a3207de6bf969793baf23b6490"
    },
    "code": 200,
    "body": {
        "tooLong2Tag": "center,1",
        "topic": "sync",
        "highPts": 1515655826286000,
        "pts": 1515623661092000,
        "seq": 0,
        "timestamp": 1515656293128
    }
}

猜测是获取未读消息,经过这两步后,新消息才会主动通知给客户端

{
    "lwp": "/r/Sync/getDiff",
    "headers": {
        "mid": "2d7b0013 0"
    },
    "body": [
        //这里的数据就是上一步响应的结果
        {
            "tooLong2Tag": "center,1",
            "topic": "sync",
            "highPts": 1515655826286000,
            "pts": 1515623661092000,
            "seq": 0,
            "timestamp": 1515656293128
        }
    ]
}

确认收到未读消息

{
    "lwp": "/r/Sync/ackDiff",
    "headers": {
        "mid": "022b0015 0"
    },
    "body": [
        // 还是上面获取状态时的响应结果
        {
            "tooLong2Tag": "center,1",
            "topic": "sync",
            "highPts": 1515655826286000,
            "pts": 1515623661092000,
            "seq": 0,
            "timestamp": 1515656293128
        }
    ]
}

标记消息为已读

{
    "lwp": "/r/IDLMessageStatus/updateToView",
    "headers": {
        "mid": "6e900034 0"
    },
    "body": [
        "33666666:3833666665", // 上一步得到的 发送者uid:接收者uid
        49827229684 // 上一步得到的消息ID
    ]
}

在控制台中输入以下代码可实现Xdebug的开启和关闭:

开启:

document.cookie = "XDEBUG_SESSION=PHPSTORM; path=/";

关闭:

document.cookie = "XDEBUG_SESSION=; expires=" + (new Date()).toGMTString() + ";";

最近接手公司以前的一个PHP项目,用PHPStorm 10打开后发现源码没有高亮显示,图标显示也和正常的PHP文件不一样:

QQ截图20160307101744.png

在Xdebug调试到该文件后,控制台有提示:

Can't compute source position. The script 'DB_active_rec.php' isn't associated with any text file type.

最后在文件列表上右键发现“Mark as PHP”的选项,执行后文件显示正常

QQ截图20160307102014.png

一直以为测试帐号不能使用网页授权获取用户基本信息的功能,因为按手册引导关注者打开授权页面后会提示:

Screenshot_2015-10-10-10-46-23.jpeg

后来才发现体验接口权限表里面的网页账号功能后面有一个修改链接,需要点击这里后在对话框里配置授权回调页面域名才行。以前一直以为是在接口配置信息里设置好URL地址就行了的,结果被坑了好久

QQ截图20151010110036.jpg

QQ截图20151010110236.jpg

$str = new \SimpleXMLElement ($xml, LIBXML_NOCDATA);
$str = json_decode(json_encode($str), true);

对于LIBXML_NOCDATA,在PHP手册上描述为:

Merge CDATA as text nodes