Category Archives: PHP

启用免费HTTPS

最近看了酷壳网耗子哥写的博客,把我的网站的http域名也改为https了

为何要使用https,而不是http?

https可以理解为一种安全的http通信协议,比如你通过浏览器访问一个网站,中间会通过网络运营商,由于http是明文传输,中间报文就可能被其他人劫持,获取你的信息,而https就可以保证传输的加密性。

我的服务器是centos 6和nginx,打开网址(https://certbot.eff.org)选择nginx和centos6,照着步骤一步步做就行了。

因为原先使用的是apache,这里顺便说下如何使用nginx替换apache

安装nginx

yum install nginx
service nginx start

nginx的网页目录默认为:/usr/share/nginx/html/

可以通过vi /etc/nginx/conf.d/default.conf来修改默认目录,我修改为原先的Apache的目录是/var/www/html

root         /var/www/html;

由于nginx只负责转发请求,并不能解析php脚本,所以我们还需要安装php解析器:php-fpm,nginx是通过把请交给php-fpm来解析php生成html页面,所以安装它:

yum install php-fpm

接着配置ngxin的域名目录并关联php-fpm

server {
        listen 80;
        root /var/www/html/blog;
        server_name www.ihnbc.cn ihnbc.cn;
        index index.shtml index.html index.htm index.php;
        charset utf-8;
        access_log /home/www.ihnbc.cn.access.log main;

        location ~.*\.(php|php5)?$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi.conf;
       }
}

php结尾的域名全部交给127.0.0.1:9000来执行,而php-fpm正好监听这个端口,启动php-fpm,重启nginx

/etc/init.d/php-fpm start
service nginx restart

配置https证书,下载certauto

wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto

然后运行:

sudo ./path/to/certbot-auto --nginx

certbot会扫描你Nginx里面的域名,选择需要配置的域名,多个用空格隔开,其他选项安装步骤执行就可以了,运行完后,certbot会在你的Nginx加上如下配置:

    listen 443 ssl http2; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/ihnbc.cn/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/ihnbc.cn/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    } # managed by Certbot

注意 listen 443 ssl后面http2是我添加上去的,http2开启后更有助于提高https的性能。

重启nginx,由于Let’s Encrypt的证书90天过期,所以你还需要配置一个任务定时去更新证书,使用cron,如下:

0 1 * * * /home/zc/certbot-auto renew

最后还有一件事要做,因为原先WordPress网站中使用的链接都是http的,所以你还需要更新网页中的http链接,不然你的链接上不会显示“安全锁”标识,使用WordPress的插件search-regex就可以批量替换(手动下载search-regex,放到wordpress的wp-content/plugins就可以了)

 

WEB服务端权限控制

在项目中很多需要用到权限的地方,整理了些我常用到的权限控制。

1. IP限制及计数

描述:绑定指定的IP可访问,并对IP访问次数记录

流程如下:

D{II5`B9NES~[FI(HG63I{C

1.1) 代码实现如下:

if($user = Statistical::check_user($_SERVER["REMOTE_ADDR"])) {
    $statistical = new Statistical($user,$query_flg); //$query_flg为接口的标识
    if(!$statistical -> check_visits()) {
    	//验证访问次数是否达到限制
    	echo '访问次数超过限制!';exit;
    }
    //获取数据
    $data = getData();

    return $data;
} else {
    //无效用户
    echo '无访问权限!';exit;
}

1.2)表的关系:

RQJ7AIJYR@9300BWXKL5X)M

1.3) 说明

check_user()方法即通过ip在ip_maping表中查找用户,若找到对应用户则在user_visit_config表中校验此用户是否还可以访问接口

校验步骤可分为:

1.3.1) 若用户第一次访问,插入记录,设置默认访问次数及有效期

1.3.2) 若不是第一次访问,若未过期:

A.访问次数没有超过当天上限,计数+1

B.访问次数超过当天上限,若为次天,则访问次数重新归1

(注:这里是每天都有固定的次数限制,超过则不可访问,要等到次天重新归1)

1.4)代码片段

/**
 * 用户检查,根据ip判断用户是否存在
 */
public static function check_user($ip) {
    $IPMappingQ = new IPMappingQuery();
    $IPMappingQ -> setIp($ip);
    $ipMapping = $IPMappingQ -> queryOne();
    if($ipMapping != null) {
        return $ipMapping -> user;
    }
    return null;
}

/**
 * 校验此用户是否可以访问接口
 */
public function check_visits() {
    try {
        $counterQ = new CounterQuery();
        $counterQ -> setUser($this->user_flg);
        $counterQ -> setInterface_flg($this->flg);
        if($counterQ -> queryCount() == 0) {
            //初次访问,插入记录
	    //(这是我根据业务实现的一种逻辑,有些时候最好先将用户可访问的接口在数据库中配置好,
	       若未查询到这个用户对应接口则返回false)
            $counterInfo = new CounterInfo();
            $counterInfo -> setUser($this->user_flg);
            $counterInfo -> setInterface_flg($this->flg);
            $counterInfo -> setVisits('1');
            $counterInfo -> setVisits_limit(DEFAULT_LIMIT);
            $counterInfo -> setValid_date(DEFAULT_VALID);
            $counterInfo -> setInsert_time(ComFunction::getNowDateTime());
            $counterInfo -> setUpdate_time(ComFunction::getNowDateTime());
            $counterInfo -> save();
            return true;
        }else {
            $counter = $counterQ -> queryOne();
            if(ComFunction::compareDateTimeStr(ComFunction::addDate($counter->getInsert_time(), $counter->getValid_time()), 
                $counter->getUpdate_time(), '>=')) { //判断是否过期
                if($counter -> getVisits() < $counter -> getVisits_limit()) {
                    $counter -> setVisits($counter->getVisits()+1);
                    $counter -> setUpdate_time(ComFunction::getNowDateTime());
                    $counter -> save();
                    return true;
                }else {
                    $last_update_date = substr($counter -> getUpdate_time(),0,10);
                    if(ComFunction::compareDateTimeStr(ComFunction::nowDate(), $last_update_date, '<')) { 
                        //如果是次天,将访问次数归1                         
                        $counter -> setVisits('1');
                        $counter -> setUpdate_time(ComFunction::getNowDateTime());
                        $counter -> save();
                        return true;
                    }
                }
            }
        }
    } catch (Exception $e) {
        return false;
    }
    return false;
}

2. 根据用户权限加载相应的模块

描述:即可指定不同的用户查看不同的功能模块。

需求:现在有一个树状的功能模块列表,每个模块都有一个对于的ID,有3种角色:超级管理员,普通管理员,一般用户;可通过配置指定角色查看指定的功能,每种角色可有多个用户。

先说说思路:有一个用户表,用户登录成功后,根据其用户名查找出用户所在用户组,根据此用户组找到此用户组可查看的模块ID列表,最后根据模块ID加载模块。

表的设计:

M{S5AL51O}I_TU{]OOHH0AG

 

同样,在做接口权限访问时也可以使用此思路,即指定某个用户组可访问指定的方法,

新建一个用户组user_group1, 将可访问的方法名(对应model_id)录入到数据库,再为这个用户组生成一个密钥(对应user_name,user_pwd), 用户可通过此密钥访问对应的方法。

 

 

PHP实现导入大SQL文件

对于mysql的大量数据导入导出,直接在服务器上使用命令,会很方便快捷,但是有时候我们不能总结直接调用命令来实现,此时我们可以使用一个脚本语言作为调用这个命令的中介,这里我是用的是php里面的system函数。

system使用说明:
string system ( string $command [, int &$return_var ] )

command: 执行的命令
return_var: 如果return_var存在,则为执行命令完后返回的结果
函数返回的结果为命令输出的最后一行。

举例:


所以如果需要通过php导入大数据,可以使用:


Dbhost 改为您的数据库服务器地址
Dbuser 改为您的数据库用户名
Password 改为您的数据库用户密码
Dbname 改为您的数据库名
backup.sql 导入的sql文件

3.在浏览器里面访问mysql.php即可完成导入,同理如果需要导出sql语句也可以使用system命令来完成,其执行的时间相对比较快。

 

memcache应对高并发量的优化

我们都知道memcahce是解决大并发量的很好一个工具,但是有一个问题值得注意,当突然有很多用户请求我们的某个页面,请求的参数相同,但对应的值却在memcahce中没有,此时这些请求都将会去查询数据库操作,瞬间对数据库照成了很大的压力。

下面我做了一个小例子来模拟这种情况。

原页面代码:

 connect("127.0.0.1",11211) or die("connect failed");

$key = $_GET['key'];
if($result = $memcache->get($key)) {
    $s = "get result form memcache: ".$key."/".$result."\n";
    file_put_contents("/var/www/html/log1.txt",$s,FILE_APPEND);
    echo $s;
}else {
    //模拟查询数据库
    sleep(5); //休眠5秒
    $result = mt_rand(1,100);
    $memcache -> set($key,$result,0,3600);
    $s = "get result not from memcache: ".$key."/".$result."\n";
    file_put_contents("/var/www/html/log2.txt",$s,FILE_APPEND);
    echo $s;
}
?>

此代码的意思是,我通过某个参数key来访问这个页面,如果此key在memcahce中存在,则在log1.txt中写入一条数据,如果不存在则休眠5秒(模拟查询数据库),在log2.txt中写入一条数据,同时将此key得到的结果放入memcahce中。

这里值得注意的是我在连接memcahce时候加了一句“or die(“connect failed”);”,即当连接报错时退出,因为有可能当memcahce的连接数超出了它本身限制的次数后,导致连接不上,从而会执行会执行else中的语句(而非memcahce中无值)。

测试并发

1)   使用ab命令测试

# ab -c 200 -n 30000 http://192.168.1.78/complicateTest.php?key=abcde

以上命令表示200个并发请求30000次

可以看到在log2文件中有许多数据,说明查询了很多次数据库:

2

可以使用对数据库查询加锁来处理,即在查询数据的时候,先在缓存中存一个值K,其他客户端需要查询数据库的时候要先判断K是否存在,若存在则休眠,如下:

 connect("127.0.0.1",11211) or die("connect failed");

$key = $_GET['key'];
getResult($memcache,$key);

function getResult($memcache,$key) {
    if($result = $memcache->get($key)) {
        $s = "get result form memcache: ".$key."/".$result."\n";
        file_put_contents("/var/www/html/log1.txt",$s,FILE_APPEND);
        echo $s;
    }else {
        $tmp_key = "_temp_".$key;
        if($memcache -> add($tmp_key, "temp key",0,60)) {
            sleep(5);
            $result = mt_rand(1,100);
            $memcache -> set($key,$result,0,3600);
            $s = "get result not from memcache: ".$key."/".$result."\n";
            file_put_contents("/var/www/html/log2.txt",$s,FILE_APPEND);
            echo $s;
            $memcache -> delete($tmp_key);
        }else {
            sleep(3);
            file_put_contents("/var/www/html/log3.txt","sleep...\n",FILE_APPEND);
            getResult($memcache, $key);
       
        }
    }
}
?>

此时我们再可以观察log2.txt中的日志,发现只有一条的,即只有一条是从数据库中查询的数据。

但如果sleep的线程如果太多的话,也可能造成进程阻塞,

另一种方法是,将数据设置在memcache的时间为永久性的,在数据中设置一个过期时间,每次获取数据时判断是否过期,若过期则加锁重新查询数据库。加锁失败则返回旧数据,但是这样做的前提是要确保memcache有这个数据,若没有则还是会返回空。所以事先需要先将用户可以查询到的数据都放到内存中,但遇到内存突然重启就会出现返回空数据的情况

 connect("127.0.0.1",11211) or die("connect failed");

$key = $_GET['key'];
print_r(getResult($memcache,$key));

function getResult($memcache,$key) {
    $result = array();
    if($result = $memcache->get($key)) {
        if($result["expired"] > strtotime(date("Y-m-d H:i:s"))) {
            //memcache中有数据,且未过期,返回原数据
            return $result;
        }else {
            return lockData($result,$memcache,$key);
        }
    }else {
        //memcache中无数据
        return lockData($result,$memcache,$key);
    }
}

//加锁,查询数据库
function lockData($result,$memcache,$key) {
    $tmp_key = "_temp_".$key;
    if($memcache -> add($tmp_key, "temp key",0,60)) {
        sleep(5);
        $result["data"] = mt_rand(1,100);
        $result["expired"] = strtotime(date("Y-m-d H:i:s")." +1 hour");
        $memcache -> set($key,$result,0,0);
        $memcache -> delete($tmp_key);
    }else {
        //若memcache中没有数据则会返回空,若有值则是返回旧数据
    }
    return $result;
}

?>

 

比较好的方式是使用gearmand来处理并发,gearmand可以确保相同的请求只执行一次,gearmand的介绍可以参考这里

1)  gearmand安装

#yum install libdrizzle libdrizzle-devel

#rpm -ivh http://dl.iuscommunity.org/pub/ius/stable/Redhat/6/x86_64/epel-release-6-5.noarch.rpm

#yum install gearmand

2)  安装php的gearmand扩展

首先要先确定有phpize,如果没有可以使用:

#yum install php-devel

#wget http://pecl.php.net/get/gearman-1.1.0.tgz

#tar zxf gearman-1.1.0.tgz

#yum install libgrearman-devel.x86_64

#yum install re2c

#cd gearman-1.1.0

#/usr/bin/phpize

#./configure

#make && make install

修改php.ini文件,加入

extension=gearman.so

3)  启动gearman

#/etc/init.d/gearman start

#service httpd restart

代码示例:

服务端gearmanWorker.php:

addServer("127.0.0.1", 4730);
  $worker->addFunction("querydb","querydb");
  while ($worker->work());


function querydb($job) {
    $key = $job -> workload();
    sleep(5);
    $result = mt_rand(1,100);
    $s = "get result not form memcache: ".$key."/".$result."\n";
    file_put_contents("/var/www/html/log2.txt",$s,FILE_APPEND);
    return $result;
}

?>

客户端complicateTest.php:

 connect("127.0.0.1",11211) or die("connect failed");

$client= new GearmanClient();
$client->addServer("127.0.0.1", 4730);

$key = $_GET['key'];
echo getResult($memcache,$key,$client);

function getResult($memcache,$key,$client) {
    if($result = $memcache->get($key)) {
       //从缓存中取
       $s = "get result form memcache: ".$key."/".$result."\n";
       file_put_contents("/var/www/html/log1.txt",$s,FILE_APPEND);
    }else {
        //memcache中无数据
        $result = $client -> doNormal("querydb",$key,$key);
        $memcache -> set($key, $result,0,3600);
    }
    return $result;
}

?>

首先启动服务端

#nohup /usr/bin/php gearmanWorker.php > log.txt 2>&1 &

使用ab命令测试:

ab -c 200 -n 10000 http://192.168.1.78/complicateTest3.php?key=sc842da

可以发现log2.txt中也只有一条记录,即只有一次从数据库中取,其他的都是从缓存中获取。
 

使用凯撒算法进行数据通信加密

凯撒加密(Caesar cipher)是一种简单的消息编码方式:它根据字母表将消息中的每个字母移动常量位k。举个例子如果k等于3,则在编码后的消息中,每个字母都会向前移动3位:a会被替换为d;b会被替换成e;依此类推。字母表末尾将回卷到字母表开头。于是,w会被替换为z,x会被替换为a。

需求

1ZNNVKOC5UF9KPYKH~$LZ$Y

 

对于使用rsa算法加密解密数据,可参考《使用rsa算法进行数据通信加密》

客户端算法:




 

服务端算法:


%-";
    $new_str = "";
    $i = 0;
    $j = 0;
    for($i = 0; $i < strlen($str); $i++){
        $c = substr($str, $i, 1);
        if($j = strpos($en_str, $c)) {
            $j = $j + $step;
            $j = $j > strlen($en_str)-1 ? $j - strlen($en_str) : $j;
            $c = substr($en_str, $j, 1);
        }
        $new_str = $new_str.$c;
    }
    return $new_str;
}
/**
 * 解密
 * @param string $str 解密字符串
 * @param int $step 位移量
 */
function caesar_decrypt($str, $step)
{
    $de_str = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/<>%-";
    $new_str = "";
    $i = 0;
    $j = 0;
    for($i = 0; $i < strlen($str); $i++){
        $c = substr($str, $i, 1);
        if($j = strpos($de_str, $c)) {
            $j = $j - $step;
            $j = $j < 0 ? $j + strlen($de_str) : $j;
            $c = substr($de_str, $j, 1);
        }
        $new_str = $new_str.$c;
    }
    return $new_str;
}

$str = "hello world;";
$str = caesar_encrypt($str, 10);
echo "encrypt: ".$str."
"; $str = caesar_decrypt($str, 10); echo "decrypt: ".$str."
"; ?>

 
以上的加密算法只能加密解密中文字符,若需要对中文加密,则需要先将中文转换字母或数字,比如可使用urlencode()方法转换,在php中直接用urlencode()方法即可,但要注意此中文一定要是UTF-8格式的,在JS中有点复杂,具体实现如下:
此JS代码参考地址
 




 

腾讯微博应用接入

公司最近开发了一款应用,需要接入到腾讯微博,下面讲讲如何将自己的应用接入到腾讯微博频道

1. 首先要申请一个腾讯账号,成为一个微博应用开发者,开发者申请地址:

http://dev.t.qq.com/developer/

注:对应应用ui的要求:宽度:760,高度700px—1200px,详细可参考:

http://wiki.open.t.qq.com/index.php/%E8%85%BE%E8%AE%AF%E5%BE%AE%E5%8D%9A%E5%BA%94%E7%94%A8%E6%8E%A5%E5%85%A5UI%E8%A7%84%E8%8C%83

2. 接着我们需要创建一个自己的应用, 这里我选的是站内应用。

为什么呢,站内应用最大的好处是:你可以在腾讯微博应用列表中搜索到这个应用,若使用的用户多,可获取腾讯微博应用的推荐

一般如果我们只想将自己的网站接入到腾讯微博,例如:我们网页上有一个很好的效果,想让用户分享到他的腾讯微博,这时我们可选择网页应用。

1

3. 接着按照要求填写你的应用信息,填写完毕后,你会获得你的App Key 和 App Secret

这里值得特别注意的是,你的应用实际地址一定要写全了,因为腾讯会通过他的地址最终回调你的实际地址,将用户的某些信息传给你的后台。如下地址,我们若要获取用户的某些信息,也必须是在main这个control层获取

2

4. 腾讯微博应用的接入,必须调用它的api, 在其官网也给出了SDK,供应用的接入使用,其SDK使用的是OAuth2.0鉴权,因为我申请的是站内应用,而且站内应用有一个特点:无需授权,也就是说,如果你的应用为站内应用,当用户访问你的应用的时候,腾讯微博就会默认将用户的某些信息传给你的后台,比如openid和openkey,

这就是调用腾讯微博api的必要两个参数(我们只需要把传过来的值保存在session中,这样需要调用其api的时候直接从session中取值就可以了),所以我使用的是OpenId&Openkey协议来实现调用api功能(当然你也可以使用它的SDK)。

5. 调用腾讯的api发微薄,参考其官方文档,调用这个接口需传入通用参数和私有参数,主要讲讲通用参数,对于通用参数,主要是获取签名值处理较为繁琐

3

6. 根据其官方给出的说明,我对发送一条微博并发送一张图片的调用做了封装,这里我采取的是POST访问,当然你也可以使用GET方式,
具体代码如下:

send_weibo_add_pic_url($content, $pic_url);
        if(stristr($curlRet, "ok")) {
            echo '1';
        } else {
            echo '0';
        }
    }
    
    private function send_weibo_add_pic_url($content, $pic_url) {
        $postUrl = "http://open.t.qq.com/api/t/add_pic_url";
        $postData = array();
        $postData['format'] = "xml";
        $postData['content'] = $content; //分享内容
        $postData['clientip'] = "";
        $postData['pic_url'] = $pic_url;
        $postData['longitude'] = "";
        $postData['latitude'] = "";
        $postData['syncflag'] = "0";
        $postData['compatibleflag'] = "0";
        $postData['appid'] = Config::$client_id;  //应用app key
        $postData['openid'] = $_SESSION['t_openid'];
        $postData['openkey'] = $_SESSION['t_openkey'];
        $postData['reqtime'] = date("Y-m-d H:i:s");
        $postData['wbversion'] = "1";
        $postData['sig'] = $this->genSig("/t/add_pic_url", $postData);
        $postData = $this->formatPostData($postData);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_URL, $postUrl);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        $curlRet = curl_exec($ch);
        curl_close($ch);
        return $curlRet;
    }
    
    /**
     * 获取签名
     * @param String $Posturl
     * @param array $postData
     */
    function genSig($Posturl, $postData) {
        $sig = "POST";
        $sig .= "&". urlencode($Posturl);
        $sig .= "&". urlencode($this->sortKey($postData));
        $appkey = Config::$client_secret . "&"; //应用 app Secret
        return base64_encode(hash_hmac("ripemd160", $sig, $appkey));
    }
    
    /**
     * key值排序
     * @param array $postData
     */
    function sortKey($postData) {
        $str = "";
        $keys = array_keys($postData);
        sort($keys);
        foreach ($keys as $k) {
            $s = $k . "=" . $postData[$k];
            $str .= "&" . $s;
        }
        $str = substr($str, 1);
        return $str;
    }
    
    /**
     * 格式化url
     * @param array $postData
     */
    function formatPostData($postData) {
        $o = "";
        foreach ($postData as $k=>$v)
        {
            $o .= "$k=".urlencode($v)."&";
        }
        $postData = substr($o, 0, -1);
        return $postData;
    }
    
}


 

使用rsa算法进行数据通信加密

RSA算法简介

它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。

4

需求:

5XEYK4X8Y_0I4R[A}8WUE@H

服务端实现

1. 首先需要在服务器上生成秘钥及证书文件,如下:

#yum install openssl

#mkdir /data/ssl

#cd /data/ssl

生成证书所需要的密钥文件:

#openssl genrsa -des3 -out service.key 1024

#openssl req -new -key service.key -out service.csr

#openssl rsa -in service.key -out service.key

1

根据密钥生成证书

#openssl x509 -req -days 365 -in service.csr -signkey service.key -out service.crt

截止,/data/ssl下会有如下文件:

service.key     service.csr     service.crt

查看密钥:

openssl asn1parse -out temp.ans -i -inform PEM < service.key

3

2. 代码示例

1) JS代码

var xmlHttp;

var rsa_n = "B4B5991A359BA0BFAB36A81688909A5128309B5460859AFAEB4251726AFF0DC8455FE6364FE5BD2C6A92B88FD551E94A63CE9F086FC1146869A48D03D2F45E1F13C0DC6BA1A2AEA0B60999AB1AEA45997ABEBF9209FE27C3EB22A82CA2AAD15BEC8EC6FC8731A8BC70B1E24D6F9EABDCE45C3329BF5748A29CF251B1723DA253"; //公钥

setMaxDigits(131);

var key = new RSAKeyPair("10001", '', rsa_n);

function showResult(b) {

if (check_fno(b)) {

alert("请输入正确航班号!")

} else {

xmlHttp = GetXmlHttpObject();

if (xmlHttp == null) {

alert("Browser does not support HTTP Request");

return

}

b = encryptedString(key,b);

var host_name = encryptedString(key,window.location.host);

var a = "getstatus.php";

a = a + "?q=" + b;

a = a + "&_host=" + host_name;

a = a + "&sid=" + Math.random();

xmlHttp.onreadystatechange = stateChanged;

xmlHttp.open("GET", a, true);

xmlHttp.send(null)

}

}

2) PHP代码:

define("CRT", "/data/ssl/service.crt"); //公钥文件
define("PEM", "/data/ssl/service.key"); //私钥文件
/**
 * 私钥解密
 *
 * @param string 密文(base64编码)
 * @param string 密钥文件(.pem/.key)
 * @param string 密文是否来源于JS的RSA加密
 * @return string 明文
 */
function privatekey_decodeing($crypttext, $fileName,$fromjs = FALSE)
{
    $key_content = file_get_contents($fileName);
    $prikeyid    = openssl_get_privatekey($key_content);
    $crypttext   = base64_decode($crypttext);
    $padding = $fromjs ? OPENSSL_NO_PADDING : OPENSSL_PKCS1_PADDING;
    if (openssl_private_decrypt($crypttext, $sourcestr, $prikeyid, $padding))
    {
        return $fromjs ? rtrim(strrev($sourcestr), "\0") : "".$sourcestr;
    }
    return FALSE;
}

/**
 * 公钥加密
 *
 * @param string 明文
 * @param string 证书文件(.crt)
 * @return string 密文(base64编码)
 */
function publickey_encodeing($sourcestr, $fileName)
{
    $key_content = file_get_contents($fileName);
    $pubkeyid    = openssl_get_publickey($key_content);
    if (openssl_public_encrypt($sourcestr, $crypttext, $pubkeyid))
    {
        return base64_encode("" . $crypttext);
    }
    return False;
}

$q=strtoupper($_GET["q"]);
$q = base64_encode(pack("H*", $q));
$q = privatekey_decodeing($q, PEM, TRUE);
/*
数据处理
*/
echo $s;