精华内容
下载资源
问答
  • 最近,对微信公众号有点兴趣,就自己研究了研究里面的一些内容,发现还挺... 我想,做微信公众号开发的,对于想获取关注了公众号的用户信息,或者说是当前与后台服务器进行交互的当前用户信息,这个功能是很重要...

        最近,对微信公众号有点兴趣,就自己研究了研究里面的一些内容,发现还挺有意思的,而且通过微信公众号可以调用一些比较有意思的接口,就比如百度开发服务平台 点击进入 里面的很有接口,就比较常见的翻译,语音识别,地理位置等等,都挺好的。好了,不多说,进入正题好了。

        我想,做微信公众号开发的,对于想获取关注了公众号的用户信息,或者说是当前与后台服务器进行交互的当前用户信息,这个功能是很重要的吧。因为,通过这个,可以直接获取到当前的用户信息,而不需要,每次都是进行自己输入信息,这个只会让用户感觉到很不适。。。所以,为了解决这个需求,那咱们来研究研究,如何获取微信的个人信息~!

    大家可以关注我的微信公众号:Java菜鸟进阶之路。便于日常阅读哦!   

    目录

     (一)思路

    (二)情况一:通过用户与服务器进行消息交互,来获取用户信息

    (三)情况二:通过点击按钮,来直接获取到用户信息

    Github仓库地址:

    彩蛋:


     (一)思路

    我们来研究一下,要想获取到个人信息,是如何一个流程呢?

    路线图:

    上面,画了一个简单的一个流程图,我想,看着这个应该觉得不难吧。是的,确实思路很简单,但是,,里面的坑也不少。接下来,我对两种情况都进行讲解。

    (二)情况一:通过用户与服务器进行消息交互,来获取用户信息

    思路:针对这种情况的话,比较简单,因为,我们在做用户与服务器进行消息交互的时候,我们可以知道,用户发送的内容是以XML的形式进行发送的,然后服务器,首先接受到XML,然后再把XML转为Map对象,再从Map对象中获取对应的内容即可。那么,发送的XML的字段是个怎么样呢?

    字段信息:

    ToUserName:发送给谁的ID
    FromUserName:发消息方的ID(其实也就是用户的OpenId)
    CreateTime:消息发送时间,时间戳
    MsgType:消息类似,有文本,图片,音频,视频,事件推送等
    Content:发送的内容

    通过这个,我想大家,再结合上面给的流程图,是不是发现了什么呢?是的,这个OpenId,我们已经获取了呀,那是不是可以直接获取到用户信息了呢?。。。。emmmmmm,这样说吧。差不多是可以的,那具体是怎么做呢?紧接着往下看,仔细看我其中的注释

    步骤:

    1:解析发送过来的XML信息格式,将其转为Map格式

    /**
         * XML格式转为map格式
         * @param request
         * @return
         */
        public static Map<String , String> xmlToMap(HttpServletRequest request){
            Map<String ,String> map = new HashMap<String , String>();
            try {
                InputStream inputStream =null;
                inputStream = request.getInputStream();
                SAXReader reader = new SAXReader();
                Document doc = reader.read(inputStream);
                Element rootElement = doc.getRootElement();
                List<Element> elements = rootElement.elements();
                for (Element el:elements) {
                    map.put(el.getName() , el.getText());
                }
                inputStream.close();
                return map ;
            } catch (Exception e) {
                e.printStackTrace();
                return null ;
            }
        }

    备注:记得导入相应的包哦。。比如dom4j还有xsreader。。

    2:获取用户的个人信息

    package com.hnu.scw.utils;
    
    import com.hnu.scw.model.AccessToken;
    import net.sf.json.JSONObject;
    
    /**
     * @author scw
     * @create 2018-01-18 16:42
     * @desc 用于获取微信用户的信息
     **/
    public class WeiXinUserInfoUtils {
        private static final String GET_USERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
    
        /**
         * 获取微信用户账号的相关信息
         * @param opendID  用户的openId,这个通过当用户进行了消息交互的时候,才有
         * @return
         */
        public static String getUserInfo(String opendID){
            AccessToken accessToken = WeiXinUtils.getAccessToken();
            //获取access_token
            String token = accessToken.getToken();
            String url = GET_USERINFO_URL.replace("ACCESS_TOKEN" , token);
            url = url.replace("OPENID" ,opendID);
            JSONObject jsonObject = WeiXinUtils.doGetStr(url);
            return jsonObject.toString();
        }
    }

    备注:传入的参数就是咱们之前说过的,FromUserName的值,这个应该不用多解释吧。因为,对于传入的XML,我们已经存入了Map中,那么直接从Map取出对应的字段信息就可以了,

    String fromUserName = map.get("FromUserName");

    3:通过上面,我们就得到了具体的用户信息的Json格式了,当然,我上面的方法将Json内容转为了String,我这里只是用于查看是否获取到信息了而已,所以,你们就根据各自的需求进行处理就可以了,该解析的就解析即可。。

    总结:

    上面的这种方法是不是很简单,这个没什么难的,而且这个根据微信公众号的开发手册也可以分析出来。

    缺点:我们发现了,这种方法,只有当用户进行了消息交互,才会有FromUserName(这时候可以等价看成是OpenId),那么我们在实际开发中,肯定遇到了一种情况,就是用户没有进行消息交互,直接点击一个菜单按钮,然后就把用户信息自动显示到了一个页面中,那这样是怎么做,方法是一样吗?不多说,继续看下面~~~~~~~~~

    (三)情况二:通过点击按钮,来直接获取到用户信息

    思路:首先,点击菜单按钮,要先到网页授权的接口去请求(主要是获取Code,这是必须要的一个参数),然后再重定向到我们自己菜单按钮实际想去的URL,然后再获取OpenId,再通过OpenId,获取用户信息。。哇塞,咦,思路挺简单的嘛。。那么,我们开始工作。。

    步骤:

    1:创建菜单

    对于这个自定义菜单的话,不是主要介绍的了,这个如果做过微信公众号开发的,应该都明白吧。所以,我这就贴一点关键代码:

    ViewButton viewButton = new ViewButton();
            viewButton.setName("view菜单");
            viewButton.setType("view");
            //viewButton.setUrl("http://myjava.ngrok.xiaomiqiu.cn/tomainpage");
            viewButton.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=XXXXXX&redirect_uri=http://myjava.ngrok.xiaomiqiu.cn/tologin/userinfo&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect");

    备注:大家,请注意,这个view菜单的URL,和我们平常的跳转的区别再哪里。。

    分析:

    知识点1:

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=XXXX

    这个就是网页授权的接口地址,其中的appid就是我们自己微信公众号申请的时候,给我们的唯一值,这个大家去微信公众号查看即可。

    知识点2:

    redirect_uri=http://myjava.ngrok.xiaomiqiu.cn/tologin/userinfo&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect");

    这个就是我们实际想要点击按钮,跳转到的页面,这个就和咱们平常的跳转是一样的,所以一定要记住,要先去授权页面,再重定向回去(主要是为了获取code参数)。

    2:配置微信公众号的网页授权域名

    备注:这个是在自己微信公众号的开发管理模块里面的,而且,我这里用的是测试号进行的(当然,如果有企业号这更加好呀。界面也是一样)

    注意点:对添加的回调页面域名:首先,不能加入http://这个,对于平常的链接,我想都有这个,这个是请求协议,但这里千万不能加入;另外,只需要写总的域名地址,不需要精确到最内层。打个比方:

    一般的:

    http://myjava.ngrok.xiaomiqiu.cn/tologin/userinfo

    这里就配置就只需要:(其实就是配置我们的服务器域名即可)

    myjava.ngrok.xiaomiqiu.cn

    3:编写,相应的处理内容(关键代码,请仔细看)

    备注:我用的是SSH(SpringMVC+Spring+Hibernate)框架来进行开发的,当然,用Servlet也可以,用SSM(SpringMVC+Spring+Mybatis)或者用SSH(Struts+Spring+Hibernate)都可以,这个根据自己的需求即可相应的改变呢!!(另外,这个几个框架,我其他的文章都有很详细的介绍了,所以自己看看相应配置即可)

    Controller层代码:

    package com.hnu.scw.controller;
    import com.hnu.scw.bean.WeiXinUser;
    import com.hnu.scw.service.WeiXinUserInfoService;
    import com.hnu.scw.utils.WeiXinUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import java.util.HashMap;
    import java.util.Map;
    /**
     * @author scw
     * @create 2018-01-18 17:47
     * @desc 获取微信用户的所有信息,这个主要是为了不要用户自己填写个人信息
     **/
    @Controller
    public class WeiXinUserInfoController {
    
        @Autowired
        private WeiXinUserInfoService userService;
    
        /**
         * 进行网页授权,便于获取到用户的绑定的内容
         * @param request
         * @param session
         * @param map
         * @return
         */
        @RequestMapping("/tologin/userinfo")
        public String check(HttpServletRequest request , HttpSession session, Map<String, Object> map) {
            //首先判断一下session中,是否有保存着的当前用户的信息,有的话,就不需要进行重复请求信息
            WeiXinUser  weiXinUser = null ;
            if(session.getAttribute("currentUser") != null){
                weiXinUser = (WeiXinUser) session.getAttribute("currentUser");
            }else {
                /**
                 * 进行获取openId,必须的一个参数,这个是当进行了授权页面的时候,再重定向了我们自己的一个页面的时候,
                 * 会在request页面中,新增这个字段信息,要结合这个ProjectConst.Get_WEIXINPAGE_Code这个常量思考
                 */
                String code = request.getParameter("code");
                try {
                    //得到当前用户的信息(具体信息就看weixinUser这个javabean)
                    weiXinUser = getTheCode(session, code);
                    //将获取到的用户信息,放入到session中
                    session.setAttribute("currentUser", weiXinUser);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            map.put("weiXinUser", weiXinUser);
            return "hello";
        }
    
        /**
         * 获取用户的openId
         * @param session
         * @param code
         * @return 返回封装的微信用户的对象
         */
        private WeiXinUser getTheCode(HttpSession session, String code) {
            Map<String , String>  authInfo = new HashMap<>();
            String openId = "";
            if (code != null)
            {
                // 调用根据用户的code得到需要的授权信息
                authInfo= userService.getAuthInfo(code);
               //获取到openId
                openId = authInfo.get("Openid");
            }
            // 获取基础刷新的接口访问凭证(目前还没明白为什么用authInfo.get("AccessToken");这里面的access_token就不行)
            String accessToken = WeiXinUtils.getAccessToken().getToken();
            //获取到微信用户的信息
            WeiXinUser userinfo = userService.getUserInfo(accessToken ,openId);
    
            return userinfo;
        }
    }

    Service层接口:

    package com.hnu.scw.service;
    import com.hnu.scw.bean.WeiXinUser;
    import java.util.Map;
    /**
     * 用于进行微信用户个人信息的操作接口
     */
    public interface WeiXinUserInfoService {
         /**
          * 获取到微信个人用户的信息
          * @param accessToken
          * @param openId
          * @return
          */
         WeiXinUser getUserInfo(String accessToken, String openId);
    
         /**
          *用于获取网页授权后的信息字段,其中主要是获取openId
          * @param code  授权码
          * @return
          */
         Map<String , String > getAuthInfo(String code);
    
         /**
          * 进行网页授权的认证
          * @param code 授权码
          * @return
          */
         Map<String,String> oauth2GetOpenid(String code);
    }
    

    Service层实现:

    package com.hnu.scw.service.imp;
    import com.hnu.scw.bean.WeiXinUser;
    import com.hnu.scw.projectconst.ProjectConst;
    import com.hnu.scw.service.WeiXinUserInfoService;
    import com.hnu.scw.utils.WeiXinUtils;
    import net.sf.json.JSONObject;
    import org.springframework.stereotype.Service;
    import java.util.HashMap;
    import java.util.Map;
    /**
     * @author scw
     * @create 2018-01-18 17:51
     * @desc 用于获取微信用户的信息
     **/
    @Service
    public class WeiXinUserInfoImlp implements WeiXinUserInfoService {
        /**
         * 获取微信用户的信息
         * @param accessToken
         * @param openId
         * @return
         */
        @Override
        public WeiXinUser getUserInfo(String accessToken, String openId) {
            WeiXinUser weixinUserInfo = null;
            // 拼接获取用户信息接口的请求地址
            String requestUrl = ProjectConst.GET_WEIXIN_USER_URL.replace("ACCESS_TOKEN", accessToken).replace(
                    "OPENID", openId);
            // 获取用户信息(返回的是Json格式内容)
            JSONObject jsonObject = WeiXinUtils.doGetStr(requestUrl);
    
            if (null != jsonObject) {
                try {
                    //封装获取到的用户信息
                    weixinUserInfo = new WeiXinUser();
                    // 用户的标识
                    weixinUserInfo.setOpenId(jsonObject.getString("openid"));
                    // 昵称
                    weixinUserInfo.setNickname(jsonObject.getString("nickname"));
                    // 用户的性别(1是男性,2是女性,0是未知)
                    weixinUserInfo.setSex(jsonObject.getInt("sex"));
                    // 用户所在国家
                    weixinUserInfo.setCountry(jsonObject.getString("country"));
                    // 用户所在省份
                    weixinUserInfo.setProvince(jsonObject.getString("province"));
                    // 用户所在城市
                    weixinUserInfo.setCity(jsonObject.getString("city"));
                    // 用户头像
                    weixinUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));
                } catch (Exception e) {
                    if (0 == weixinUserInfo.getSubscribe()) {
                        System.out.println("用户并没有关注本公众号");
                    } else {
                        int errorCode = jsonObject.getInt("errcode");
                        String errorMsg = jsonObject.getString("errmsg");
                        System.out.println("由于"+errorCode +"错误码;错误信息为:"+errorMsg+";导致获取用户信息失败");
                    }
                }
            }
            return weixinUserInfo;
        }
    
        /**
         * 进行用户授权,获取到需要的授权字段,比如openId
         * @param code 识别得到用户id必须的一个值
         * 得到网页授权凭证和用户id
         * @return
         */
        @Override
        public Map<String, String> oauth2GetOpenid(String code) {
            //自己的配置appid(公众号进行查阅)
            String appid = ProjectConst.PROJECT_APPID;
            //自己的配置APPSECRET;(公众号进行查阅)
            String appsecret = ProjectConst.PROJECT_APPSECRET;
            //拼接用户授权接口信息
            String requestUrl = ProjectConst.GET_WEBAUTH_URL.replace("APPID", appid).replace("SECRET", appsecret).replace("CODE", code);
            //存储获取到的授权字段信息
            Map<String, String> result = new HashMap<String, String>();
            try {
                JSONObject OpenidJSONO = WeiXinUtils.doGetStr(requestUrl);
                //OpenidJSONO可以得到的内容:access_token expires_in  refresh_token openid scope
                String Openid = String.valueOf(OpenidJSONO.get("openid"));
                String AccessToken = String.valueOf(OpenidJSONO.get("access_token"));
                //用户保存的作用域
                String Scope = String.valueOf(OpenidJSONO.get("scope"));
                String refresh_token = String.valueOf(OpenidJSONO.get("refresh_token"));
                result.put("Openid", Openid);
                result.put("AccessToken", AccessToken);
                result.put("scope", Scope);
                result.put("refresh_token", refresh_token);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
        /**
         * 获取到微信用户的唯一的OpendID
         * @param code  这是要获取OpendId的必须的一个参数
         * @return
         */
        @Override
        public Map<String , String> getAuthInfo(String code) {
            //进行授权验证,获取到OpenID字段等信息
            Map<String, String> result = oauth2GetOpenid(code);
            // 从这里可以得到用户openid
            String openId = result.get("Openid");
    
            return result;
        }
    }

    4:GET请求接口的代码:

    package com.hnu.scw.utils;
    import com.hnu.scw.menu.BaseButton;
    import com.hnu.scw.menu.ClickButton;
    import com.hnu.scw.menu.CustomeMenu;
    import com.hnu.scw.menu.ViewButton;
    import com.hnu.scw.model.AccessToken;
    import net.sf.json.JSONObject;
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.util.EntityUtils;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    
    /**
     * @author scw
     * @create 2018-01-17 14:13
     * @desc 用户获取access_token,众号调用各接口时都需使用access_token
     **/
    public class WeiXinUtils {
        /**
         * Get请求,方便到一个url接口来获取结果
         * @param url
         * @return
         */
        public static JSONObject doGetStr(String url){
            DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            JSONObject jsonObject = null;
            try{
                HttpResponse response = defaultHttpClient.execute(httpGet);
                HttpEntity entity = response.getEntity();
                if(entity != null){
                    String result = EntityUtils.toString(entity, "UTF-8");
                    jsonObject = JSONObject.fromObject(result);
                }
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return jsonObject;
        }

    5:获取Access_Token代码:(这个就是在4中的类中的方法)

    /**
         * 获取access_token
         * @return
         */
        public static AccessToken getAccessToken(){
            AccessToken accessToken = new AccessToken();
            String url = ACCESS_TOKEN_URL.replace("APPID" ,APPID).replace("APPSECRET",APPSECRET);
            JSONObject jsonObject = doGetStr(url);
            if(jsonObject !=null){
                accessToken.setToken(jsonObject.getString("access_token"));
                accessToken.setExpireIn(jsonObject.getInt("expires_in"));
            }
            return accessToken;
        }

    6:Access_Token的实体类

    package com.hnu.scw.model;
    /**
     * @author scw
     * @create 2018-01-17 14:35
     * @desc 封装AccessToken的实体
     **/
    public class AccessToken {
        private String token;
        private int expireIn;
    
        public String getToken() {
            return token;
        }
        public void setToken(String token) {
            this.token = token;
        }
        public int getExpireIn() {
            return expireIn;
        }
        public void setExpireIn(int expireIn) {
            this.expireIn = expireIn;
        }
    }

    7:用户信息的实体类

    package com.hnu.scw.bean;
    /**
     * @author scw
     * @create 2018-01-18 17:11
     * @desc 对于微信用户本身存在的信息的一个javabean,不需要在数据库中进行处理
     **/
    public class WeiXinUser {
        // 用户的标识
        private String openId;
        // 关注状态(1是关注,0是未关注),未关注时获取不到其余信息
        private int subscribe;
        // 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
        private String subscribeTime;
        // 昵称
        private String nickname;
        // 用户的性别(1是男性,2是女性,0是未知)
        private int sex;
        // 用户所在国家
        private String country;
        // 用户所在省份
        private String province;
        // 用户所在城市
        private String city;
        // 用户的语言,简体中文为zh_CN
        private String language;
        // 用户头像
        private String headImgUrl;
        public String getOpenId() {
            return openId;
        }
        public void setOpenId(String openId) {
            this.openId = openId;
        }
        public int getSubscribe() {
            return subscribe;
        }
        public void setSubscribe(int subscribe) {
            this.subscribe = subscribe;
        }
        public String getSubscribeTime() {
            return subscribeTime;
        }
        public void setSubscribeTime(String subscribeTime) {
            this.subscribeTime = subscribeTime;
        }
        public String getNickname() {
            return nickname;
        }
        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
        public int getSex() {
            return sex;
        }
        public void setSex(int sex) {
            this.sex = sex;
        }
        public String getCountry() {
            return country;
        }
        public void setCountry(String country) {
            this.country = country;
        }
        public String getProvince() {
            return province;
        }
        public void setProvince(String province) {
            this.province = province;
        }
        public String getCity() {
            return city;
        }
        public void setCity(String city) {
            this.city = city;
        }
        public String getLanguage() {
            return language;
        }
        public void setLanguage(String language) {
            this.language = language;
        }
        public String getHeadImgUrl() {
            return headImgUrl;
        }
        public void setHeadImgUrl(String headImgUrl) {
            this.headImgUrl = headImgUrl;
        }
    }

    8:一些静态常量的接口地址:

    package com.hnu.scw.projectconst;
    
    /**
     * @author scw
     * @create 2018-01-18 15:31
     * @desc 项目相关的静态量
     **/
    public class ProjectConst {
        /**
         * 用于获取当前与微信公众号交互的用户信息的接口(一般是用第一个接口地址)
         */
        public static final String GET_WEIXIN_USER_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";
        public final static String GetPageUsersUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
    
        /**
         * 用于进行网页授权验证的接口URL,通过这个才可以得到opendID等字段信息
         */
        public final static String GET_WEBAUTH_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    
        /**
         * 用于进行当点击按钮的时候,能够在网页授权之后获取到code,再跳转到自己设定的一个URL路径上的接口,这个主要是为了获取之后于
         * 获取openId的接口相结合
         * 注意:参数:toselfURL  表示的是当授权成功后,跳转到的自己设定的页面,所以这个要根据自己的需要进行修改
         */
        public final static String Get_WEIXINPAGE_Code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=toselfURL&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";
        /**
         * 获取access_token的URL
         */
        private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    
    }

    9:大功告成。。。。哇塞,完美解决。。

    总结:

    这种方式,相对于上面的话,好处就在于,不需要进行消息交互就可以获取到用户的信息,这样其实更符合我们的业务需求,相对于更加好。但是,第一种情况也是有实用价值的,所以,我们要客观的进行评价和使用~~~~当然,这里面还有很多的可以优化的地方,就是,比如获取Access_Token,我们一般都是弄到本地,因为微信公众号一天请求的次数有限制(2000),所以这可以进行优化哦。。。。其他的根据需求来就可以啦!!!!!!!!

         好了,这个就介绍这个多了,都是经过本人亲自测试通过后的代码,所以,大家可以放心的使用,有问题的话,可以进行留言交流哦。。。

    Github仓库地址:

    https:https://github.com/qq496616246/WeChatCode.git

    git:git@github.com:qq496616246/WeChatCode.git

    彩蛋

    如果你想利用闲暇零散的学习技术,那么不妨关注我的公众号阅读你想要的文章哦!

    公众号搜索:Java菜鸟进阶之路

    展开全文
  • PHP获取客户端(浏览器)信息;PHP获取客户端系统信息;PHP获取服务器基本信息

    一、PHP获取客户端(浏览器)信息函数

    /**  
     * 获取客户端浏览器信息
     * @param   null  
     * @author  https://blog.jjonline.cn/phptech/168.html
     * @return  string   
     */  
    function get_broswer()
    {
        $sys = $_SERVER['HTTP_USER_AGENT'];  //获取用户代理字符串  
        if (stripos($sys, "Firefox/") > 0) {  
            preg_match("/Firefox\/([^;)]+)+/i", $sys, $b);  
            $exp[0] = "Firefox";  
            $exp[1] = $b[1];  	//获取火狐浏览器的版本号  
        } elseif (stripos($sys, "Maxthon") > 0) {  
            preg_match("/Maxthon\/([\d\.]+)/", $sys, $aoyou);  
            $exp[0] = "傲游";  
            $exp[1] = $aoyou[1];  
        } elseif (stripos($sys, "MSIE") > 0) {  
            preg_match("/MSIE\s+([^;)]+)+/i", $sys, $ie);  
            $exp[0] = "IE";  
            $exp[1] = $ie[1];  //获取IE的版本号  
        } elseif (stripos($sys, "OPR") > 0) {  
            preg_match("/OPR\/([\d\.]+)/", $sys, $opera);  
            $exp[0] = "Opera";  
            $exp[1] = $opera[1];    
        } elseif(stripos($sys, "Edge") > 0) {  
            //win10 Edge浏览器 添加了chrome内核标记 在判断Chrome之前匹配  
            preg_match("/Edge\/([\d\.]+)/", $sys, $Edge);  
            $exp[0] = "Edge";  
            $exp[1] = $Edge[1];  
        } elseif (stripos($sys, "Chrome") > 0) {  
            preg_match("/Chrome\/([\d\.]+)/", $sys, $google);  
            $exp[0] = "Chrome";  
            $exp[1] = $google[1];  //获取google chrome的版本号  
        } elseif(stripos($sys,'rv:')>0 && stripos($sys,'Gecko')>0){  
            preg_match("/rv:([\d\.]+)/", $sys, $IE);  
            $exp[0] = "IE";  
            $exp[1] = $IE[1];  
        }else {  
            $exp[0] = "未知浏览器";  
            $exp[1] = "";   
        }  
        return $exp[0].'('.$exp[1].')';  
    }

    二、获取客户端系统信息

    /**  
     * 获取客户端操作系统信息,包括win10 
     * @param   null  
     * @author  https://blog.jjonline.cn/phptech/168.html 
     * @return  string   
     */  
    function get_os(){  
        $agent = $_SERVER['HTTP_USER_AGENT'];  
        $os = false;
    
        if (preg_match('/win/i', $agent) && strpos($agent, '95'))  
        {  
          $os = 'Windows 95';  
        }  
        else if (preg_match('/win 9x/i', $agent) && strpos($agent, '4.90'))  
        {  
          $os = 'Windows ME';  
        }  
        else if (preg_match('/win/i', $agent) && preg_match('/98/i', $agent))  
        {  
          $os = 'Windows 98';  
        }  
        else if (preg_match('/win/i', $agent) && preg_match('/nt 6.0/i', $agent))  
        {  
          $os = 'Windows Vista';  
        }  
        else if (preg_match('/win/i', $agent) && preg_match('/nt 6.1/i', $agent))  
        {  
          $os = 'Windows 7';  
        }  
          else if (preg_match('/win/i', $agent) && preg_match('/nt 6.2/i', $agent))  
        {  
          $os = 'Windows 8';  
        }else if(preg_match('/win/i', $agent) && preg_match('/nt 10.0/i', $agent))  
        {  
          $os = 'Windows 10';#添加win10判断  
        }else if (preg_match('/win/i', $agent) && preg_match('/nt 5.1/i', $agent))  
        {  
          $os = 'Windows XP';  
        }  
        else if (preg_match('/win/i', $agent) && preg_match('/nt 5/i', $agent))  
        {  
          $os = 'Windows 2000';  
        }  
        else if (preg_match('/win/i', $agent) && preg_match('/nt/i', $agent))  
        {  
          $os = 'Windows NT';  
        }  
        else if (preg_match('/win/i', $agent) && preg_match('/32/i', $agent))  
        {  
          $os = 'Windows 32';  
        }  
        else if (preg_match('/linux/i', $agent))  
        {  
          $os = 'Linux';  
        }  
        else if (preg_match('/unix/i', $agent))  
        {  
          $os = 'Unix';  
        }  
        else if (preg_match('/sun/i', $agent) && preg_match('/os/i', $agent))  
        {  
          $os = 'SunOS';  
        }  
        else if (preg_match('/ibm/i', $agent) && preg_match('/os/i', $agent))  
        {  
          $os = 'IBM OS/2';  
        }  
        else if (preg_match('/Mac/i', $agent) && preg_match('/PC/i', $agent))  
        {  
          $os = 'Macintosh';  
        }  
        else if (preg_match('/PowerPC/i', $agent))  
        {  
          $os = 'PowerPC';  
        }  
        else if (preg_match('/AIX/i', $agent))  
        {  
          $os = 'AIX';  
        }  
        else if (preg_match('/HPUX/i', $agent))  
        {  
          $os = 'HPUX';  
        }  
        else if (preg_match('/NetBSD/i', $agent))  
        {  
          $os = 'NetBSD';  
        }  
        else if (preg_match('/BSD/i', $agent))  
        {  
          $os = 'BSD';  
        }  
        else if (preg_match('/OSF1/i', $agent))  
        {  
          $os = 'OSF1';  
        }  
        else if (preg_match('/IRIX/i', $agent))  
        {  
          $os = 'IRIX';  
        }  
        else if (preg_match('/FreeBSD/i', $agent))  
        {  
          $os = 'FreeBSD';  
        }  
        else if (preg_match('/teleport/i', $agent))  
        {  
          $os = 'teleport';  
        }  
        else if (preg_match('/flashget/i', $agent))  
        {  
          $os = 'flashget';  
        }  
        else if (preg_match('/webzip/i', $agent))  
        {  
          $os = 'webzip';  
        }  
        else if (preg_match('/offline/i', $agent))  
        {  
          $os = 'offline';  
        }  
        else  
        {  
          $os = '未知操作系统';  
        }  
        return $os;    
    }

    三、获取服务器基本信息

    public function osinfo()
    {
    	$info = array(
    		'操作系统'	=>	PHP_OS,
    		'运行环境'	=>	$_SERVER["SERVER_SOFTWARE"],
    		'主机名'		=>	$_SERVER['SERVER_NAME'],
    		'WEB服务端口'	=>	$_SERVER['SERVER_PORT'],
    		'网站文档目录'	=>	$_SERVER["DOCUMENT_ROOT"],
    		'浏览器信息'	=>	substr($_SERVER['HTTP_USER_AGENT'], 0, 40),
    		'通信协议'	=>	$_SERVER['SERVER_PROTOCOL'],
    		'请求方法'	=>	$_SERVER['REQUEST_METHOD'],
    		// 'ThinkPHP版本'=>THINK_VERSION,
    		'PHP版本'	=>	PHP_VERSION,	 
    		'上传附件限制'	=>	ini_get('upload_max_filesize'),
    		'执行时间限制'	=>	ini_get('max_execution_time').'秒',
    		'服务器时间'	=>	date("Y年n月j日 H:i:s"),
    		'北京时间'	=>	gmdate("Y年n月j日 H:i:s",time()+8*3600),
    		'服务器域名/IP'	=>	$_SERVER['SERVER_NAME'].' [ '.gethostbyname($_SERVER['SERVER_NAME']).' ]',
    		'剩余空间'	=>	round((disk_free_space(".")/(1024*1024)),2).'M',
    		'当前用户的IP地址'=>	$_SERVER['REMOTE_ADDR'],
    	);
    
    	return $info;
    }

    四、参考资料

    《最新PHP获取客户端浏览以及操作系统信息》【获取客户端浏览器函数和获取客户端系统函数是照搬过来的,感谢大神!】

    展开全文
  • 微信小程序 获取用户信息(包括openId等敏感信息)

    万次阅读 多人点赞 2017-08-07 17:34:01
    获取用户的基本信息 wx.getUserInfo(OBJECT)获取用户信息 wx.getUserInfo({ success: function(res) { var userInfo = res.userInfo //用户基本信息 var nickName = userInfo.nickName //用户名

    想来跟微信小程序也是有缘。
    现在在公司主要负责起了小程序这块。

    1. 获取用户的基本信息
      wx.getUserInfo(OBJECT)获取用户信息
    wx.getUserInfo({
      success: function(res) {
        var userInfo = res.userInfo //用户基本信息
        var nickName = userInfo.nickName //用户名
        var avatarUrl = userInfo.avatarUrl //头像链接
        var gender = userInfo.gender //性别 0:未知、1:男、2:女
        var province = userInfo.province //所在省
        var city = userInfo.city //所在市
        var country = userInfo.country //所在国家
      }
    })

    2.获取系统信息
    wx.getSystemInfo(OBJECT)获取系统信息

    wx.getSystemInfo({
      success: function(res) {
        console.log(res.model)    //  手机型号
        console.log(res.pixelRatio) 
        console.log(res.windowWidth)
        console.log(res.windowHeight)
        console.log(res.language)
        console.log(res.version)
        console.log(res.platform)
        console.log(res.system) //  操作系统版本
      }
    })

    3.获取openId (用户唯一标识)和session_key
    wx.login(OBJECT) 调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key)。

    这里写图片描述

    获取到code之后请求https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code接口

     wx.login({
            //获取code
            success: function (res) {
              var code = res.code; //返回code
              console.log(code);
              var appId = '...';
              var secret = '...';
              wx.request({
                url: 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appId + '&secret=' + secret + '&js_code=' + code + '&grant_type=authorization_code',
                data: {},
                header: {
                  'content-type': 'json'
                },
                success: function (res) {
                  var openid = res.data.openid //返回openid
                  console.log('openid为' + openid);
                }
              })
            }
          })

    此时如果你未勾选项目中的“开发环境不效验请求域名、TLS版本以及HTTPS证书”则会报错
    这里写图片描述
    这里写图片描述
    会说接口https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code不是一个合法域名。此时勾选项目中的“开发环境不效验请求域名、TLS版本以及HTTPS证书”则可避免。但是…你项目要上线肯定有bug啊。然后你就想着去把这个链接加到你的服务器域名里面去,但是发现竟然不允许这样操作…

    此链接中有原因http://kf.qq.com/faq/1706236NjINj1706236VRZBR.html

    如果在配置服务器域名中填写了“api.weixin.qq.com”会出现上述错误提示。出于安全考虑,为避免开发者将AppSecret放置在小程序的前端代码内,平台禁止设置此域名。
    小程序的开发者密码(AppSecret)是一个非常重要的字段,使用该密码可以调用小程序的所有后台接口。请不要将该字段放置在微信小程序的前端代码中,因为微信手机客户端容易被反编译并轻松获得Appsecret,造成重大的安全威胁。开发者应将Appsecret保存到后台服务器中,通过服务器使用Appsecert获取Accesstoken。微信公众平台小程序后台的服务器地址设置也将禁止将“api.weixin.qq.com”域名的配置,所有对于“api.weixin.qq.com”域名下的接口请求请全部通过后台服务器发起,请勿直接通过小程序的前端代码发起。

    所以解决办法就是把code传给后台,让后台去请求微信的官方接口获得openId和session-key。

    其实微信小程序官方的登录时序图也是这样画的
    这里写图片描述
    将code传至后台服务器,让服务器去访问微信服务器得到openId和session_key。

    OK,结束。

    展开全文
  • 0x00:简介 banner 信息来表示欢迎语,其中会包含一些敏感信息,所以获取 banner 也属于信息搜集的范畴。在渗透测试中,典型的 4xx、5xx 信息泄露就属于 ...banner 信息获取的基础是在和目标建立链接后的,只有...

    0x00:简介

    banner 信息来表示欢迎语,其中会包含一些敏感信息,所以获取 banner 也属于信息搜集的范畴。在渗透测试中,典型的 4xx、5xx 信息泄露就属于 banner 泄露的一种。在 banner 信息中,可以获取到软件开发商、软件名称、服务类型、版本号等。而版本号有时候就会存在公开的 CVE 问题,可以直接进行利用。

    banner 信息获取的基础是在和目标建立链接后的,只有建立的链接,才可以获取到相应的 banner 信息,当目标对 banner 信息进行隐藏或者配置了禁止读取时,这时的 banner 则获取不到。

    0x01:nc

    nc 在建立链接后会返回相应端口的 banner,命令格式为 nc -nv 1.1.1.1 xx,ip 直接跟端口即可,示例如下:

    请输入图片描述

    上图中,21,22,23,25 端口都是开放的,并返回了 banner 信息,包括使用的服务和版本号。24 端口是没有开放的,直接返回了拒绝链接。

    0x02:scapy

    除了 nc 外,python 中的 socket 模块也可以用来获取 banner 信息,之前在主机发现、端口扫描时经常用到 scapy,而在这里 scapy 不合适。scapy 可以理解为是用来构造数据包、发送数据包、修改数据包以及接收数据包的。而 socket 可以理解为是用来建立链接发送数据和接收数据的,用于网络服务,网络编程。进入 python 环境,简单的利用 socket 进行链接目标并返回 banner 信息的示例如下:

    请输入图片描述

    以上过程可写为 python 脚本,脚本示例如下:

    #!/usr/bin/python
    import socket
    import select
    import sys
    
    if len(sys.argv)!=4:
        print"error:./banner.py 1.1.1.1 1 100"
        sys.exit()
    
    ip = sys.argv[1]
    start = int(sys.argv[2])
    end = int(sys.argv[3])
    
    for port in range(start,end):
        try:
            banner = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            banner.connect((ip,port))
            ready = select.select([banner],[],[],1)
            if ready[0]:
                print"TCP port "+str(port)+"-"+banner.recv(1024)
                banner.close()
        except:
            pass
    

    先说一下上面脚本的总体流程,首先是需要四个参数,一个是 ip 地址,一个是起始端口号,一个是结束端口号,在 sys 系统模块的 argv 参数这里,作用是从外部获取输入的内容作为参数,文件名也属于参数,所以是四个。然后分别分别分配给变量 ip、start、end,循环端口号给到 socket,最后获取 banner 信息。

    再说一下细节,首先是 socket.socket 的参数,第一个参数是输入地址类型,第二个是输入套接字类型。socket.AF_INET 是用于服务之间的网络通信。socket.SOCK_STREAM 是用于 TCP,这两个参数的选择项如下:

    第一个地址类型:
    socket.AF_UNIX:用于 Unix 系统进程间的通信。
    socket.AF_INET:服务器之间的网络通信。
    socket.AF_INET6:使用 IPv6 进行通信。

    第二个套接字类型:
    socket.SOCK_STREAM:流式的 socket,用于 TCP。
    socket.SOCK_DGRAM:数据包式的 socket,用于 UDP。

    而经常组合用到的有两种,一种是 TCP 的 socket,一种是 UDP 的 socket,他们分别如下:

    TCP:socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    UDP:socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    脚本中的 connect 用来链接目标。select 作用在于获取链接状态,经常和 socket 一起使用,四个参数分别是链接状态,写入状态,错误状态和超时时间,脚本中只指定了第一个参数链接状态,写入和错误留的空,最后超时为 1 秒,即每过 1 秒 select 就会获取一下 banner 的链接状态。

    脚本中 select 的作用在于,recv 获取字符的时候如果没有返回就会挂起,这样会影响后续的其他端口 banner 信息获取,所以用 select 指定链接状态和超时时间。连接后会返回 banner 信息,用 recv 读取然后打印,如果没有内容返回则不做任何处理。执行结果如下:

    请输入图片描述

    结果显示获取到了 21 和 22 的 banner 信息,看下 wireshark 的抓包过程:

    请输入图片描述

    通过 wireshark 抓包可以发现,如果端口是没开放的,则是返回的 RST/ACK 包,则没有 banner 信息,如果端口是开放状态,则进行了整个 tcp 的三次握手。

    0x03:dmitry

    除了 nc 和 scapy 外,dmitry 也有此功能,dmitry 也属于端口发现中全链接扫描方式的一种,使用简单,参数如下:

    请输入图片描述

    参数不多,很简单的一个工具,p 参数用来做 tcp 扫描,b 参数用来获取 banner 信息,dmitry 默认扫描 150 个端口,执行如下:

    请输入图片描述

    获取 banner 信息如下:

    请输入图片描述

    0x04:nmap

    强大的 nmap 肯定也有获取 banner 的方法,只不过是通过脚本实现的,因为 banner 获取是建立在连接的基础上的,所以需要用到 sT 参数,sT 用来连接目标,其命令和结果如下:

    请输入图片描述

    这里就体现出了 nmap 的强大,业界把 nmap 称为神器,电影也有 nmap 的身影,是有理由的。单从 banner 这块就获取到了其他命令没有获取到的一些结果,例如 23,25,53,80 这些,其 nmap 使用的 banner 脚本写的也很好,感兴趣可以看一下。

    0x05:amap

    还有一个工具是 amap,这个命令是用来发现端口后面跑的是什么服务,其中 B 参数是专门用来获取 banner 信息的,参数说明如下:

    请输入图片描述

    执行结果如下:

    请输入图片描述

    0x06:总结

    这边博客记录了在服务扫描时获取 banner 的一些方法,其中有 nc、scapy、nmap、dmitry、amap,通过上面介绍,可以发现 nmap 相对来说是更全面的。


                                                                          公众号推荐:aFa攻防实验室

                             分享关于信息搜集、Web安全、内网安全、代码审计、红蓝对抗、Java、Python等方面的东西。

                                                                          

    展开全文
  • 微信小程序授权 获取用户信息

    万次阅读 多人点赞 2018-05-30 18:25:37
    获取用户信息(用户信息获取unionId、openId)请移步到这里 用户打开小程序时,直接弹框获取用户信息授权,可能会立马懵圈: 你是谁? 我在哪里? 我为什么要同意?…… 相当一部分用户下意识会拒绝...
  • 通过PackageInfo 能获取哪些信息

    千次阅读 2012-05-28 12:30:51
    包的信息,也包括了系统预装的应用软件的信息,要区分这两类软件可使用以下方法: a. 从 packageInfoList 获取的 packageInfo ,再通过 packageInfo. applicationInfo 获取 applicationInfo 。 b. 判断 ...
  • [Python]使用TuShare能获取哪些信息?

    千次阅读 2017-10-22 20:31:35
    windows下先前装了Anaconda3,然后用pip 直接装tushare即可。...居民消费指数,可以通过ts.get_cpi()函数获取(一次会获取322条,部分展示) ts.get_latest_news()函数可以查看最近的新闻,会返回80条
  • 由于项目需求,开发地图时需要对地图点信息进行聚合,而且还需要获取该聚合点下的点有哪些,查看相关资料,并没有对这一问题进行介绍,如何解决这个问题?     在地图初始化时,地图上的点位是...
  • js获取浏览器信息和页面信息

    千次阅读 2015-01-06 13:24:35
    js获取浏览器信息和页面信息
  • 转载 2017-03-28 作者:律师''''小窝 PHPInfo()函数主要用于网站建设过程中测试搭建的PHP环境是否正确,很多网站在测试完毕后并没有及时删除,因此当访问这些测试页面时,会输出服务器的关键信息,这些信息的泄露将...
  • Android系统信息和Apk应用信息获取

    千次阅读 2016-06-06 17:03:44
    获取Android系统信息和Apk应用信息
  • 根据当前浏览器ip获取地理信息包含省市区街道,PC浏览器获取地理位置信息包含省市区街道
  • Apach服务器下可以直接使用 PHP自带函数获取客户端HTTP请求头信息/* 作用:获取客户端HTTP请求所有头信息(header) 参数:无。 返回:HTTP请求所有头信息数组 */ Array getallheaders(); 实例:&lt;?...
  • php获取服务器信息,包括操作系统、php版本及运行环境和PHP信息   解决方法: $s = php_uname('s');//获取系统类型 获取php版本及运行环境和获取PHP信息:http://www​.yayihouse....
  • banner的获取: banner 信息来表示欢迎语,其中会包含一些敏感信息,所以获取 banner 也属于信息搜集的范畴。在渗透测试中,典型的 4xx、5xx 信息泄露就属于 ...banner 信息获取的基础是在和目标建立链接后的,建...
  • Qt 之 获取文件信息

    千次阅读 2019-02-22 15:42:23
    QFileInfo类为我们提供了与系统无关的文件信息包含文件的name和在文件系统中的位置,文件的访问权限。是否是目录或符合连接等。并且,通过该类,可以修改文件的大小和最后修改、读取的时间。同时,QFileInfo类也...
  • Android Build类获取系统信息

    万次阅读 2015-03-31 11:27:27
    在Android中可以Build类来获取一些系统信息,本文介绍了Build类的使用,可获取的系统信息列表。并详细介绍了Build类获取系统信息的流程,以及Build类获取到系统信息的来源。最后介绍了如何修改部分系统信息
  • 原文地址:... 二、获取发起人 historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstance.getId()).singleResult().getStartUserId();//获取发起人
  • kubernetes 自从1.7开始,可以在pod 的container 内获取pod的spec,metadata 等信息。 具体方法可以通过env获取: env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName ...
  • Java 获取所有子类信息

    千次阅读 2019-06-14 16:39:47
    我以前的博客(Java Scala获取注解的类信息)介绍过通过Reflections工具通过使用特定注解的类的信息,其实本工具也可以获取接口,抽象类,类等的所有子类信息。使用方法如下: Reflections reflections = new ...
  • Android系统信息获取

    千次阅读 2018-01-04 15:07:40
    类似“安兔兔”的手机跑分软件可以非常清楚地检查手机系统的配置信息和软硬件信息,下面我们就来看看如何获取这些信息。  要获取系统的配置信息,通常可以从以下两个方面获取。 android.os.BuildSystemPrope
  • Android系统信息获取 之十四:获取WIFI热点相关信息 当在Android设备终端上使用Wifi热点的时候,需要获知Wifi热点的运行状态,热点是否打开,连接到该WIFI热点的设备数量,以及连接设备的具体IP和MAC地址。 使用re...
  • JS--AJAX获取JSON数据、获取头部信息

    千次阅读 2019-09-29 23:08:35
    通过XMLHttpRequest对象的responseText属性获取返回的JSON数据字符串,然后可以使用evaluate()方法将其解析为本地JavaScript对象,从该对象中再读取任何想要的信息。 示例:将JSON对象字符串转换为本地对象 <%-- ...
  • Python解析照片EXIF信息获取坐标位置

    千次阅读 多人点赞 2019-12-10 09:26:38
    每张图片都包含EXIF信息,它是可交换图像文件的缩写,是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。EXIF可以附加于JPEG、TIFF、RIFF等文件之中,为其增加有关数码相机拍摄信息的内容和索引...
  • Android获取系统播放音乐信息

    千次阅读 2018-10-08 11:14:44
    如题,需要获取播放的音乐信息,原理是播放音乐的时候会发送四种广播,因此可以使用广播接收器拦截一下广播…… 但是!!!!当系统正在播放音乐的时候,我还不知道怎么获取音乐信息QAQ 要是哪位知道怎么获取,求...
  • 使用FFmpeg获取视频信息

    千次阅读 2019-01-18 10:31:43
    //之前在网上找了很多例子使用ffmpeg获取视频参数,发现正则有问题,加以改良,希望其他人不要被误导 /** * 广州第一靓仔-Stone * 获取视频的分辨率 * @param $strInfoArray * @param string $fileName */ ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,923,179
精华内容 769,271
关键字:

信息获取包括哪些