龚哥哥 爱生活、做自己!
PHP采用Swoole扩展开发高性能WebSocket
发表于 2016-9-17 | 浏览(2229) | PHP

需要安装PHP Swoole扩展,官网地址:http://www.swoole.com/

安装教程可查看本博客中swoole安装

1、index.html 内容如下

<!DOCTYPE html>
<head>
<title>socket demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="./jquery-2.1.3.min.js"></script>
</head>
<body>
<input type="text" id="msg" />
<button id="send">发送</button>
</body>
</html>
<script>
$(function()
{
	// 创建socket对象
	var socket = new WebSocket('ws://'+document.domain+':9501');

	// 打开Socket 
	socket.onopen = function(event)
	{

		$('#send').on('click', function()
		{
			var msg = $('#msg').val();
			socket.send(msg);
			console.log(msg);
		});
		// 发送一个初始化消息
		socket.send("客户端初始化!"); 

		// 监听消息
		socket.onmessage = function(event) { 
			console.log("客户端监听到的消息:", event); 
		}; 

		// 监听Socket的关闭
		socket.onclose = function(event) { 
		console.log("Socket关闭了", event); 
		}; 

	  // 关闭Socket.... 
	  //socket.close() 
	};
});
</script>

2、web_socket.php 内容如下

<?php

// 本机的ip
// 通过命令行运行 cli
$server = new swoole_websocket_server("192.168.0.110", 9501);

// 握手成功回调
$server->on('open', function(swoole_websocket_server $server, $request)
{
    echo "server: handshake success with fd{$request->fd}\n";
});

// 消息监听
$server->on('message', function(swoole_websocket_server $server, $frame)
{
    echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
    $server->push($frame->fd, "this is server {$frame->data}");
});

// 关闭监听
$server->on('close', function($ser, $fd)
{
    echo "client {$fd} closed\n";
});

// http请求监听, 如果监听了Request则可以通过http访问
// 通过 http://192.168.0.110:9501 访问
$server->on('Request', function($req, $respone)
{
    // $req->get, $req->post
    if(!empty($req->get))
    {
        // 使用全局变量
        global $server;

        // 服务器推送消息给客户端
        // 参数1 socketID, 参数2 推送内容
        $server->push(1, "this is server hello request {$req->get['msg']}");

        // 响应完成
        $respone->end("success");
    }
});

// 开始
$server->start();

?>

3、在命令行运行web_socket.php

php web_socket

4、客户端在浏览器上访问,可发送消息到服务器并且响应服务器推送的消息

http://192.168.0.110/index.html

5、服务器端推送消息给客户端,在客户端页面可看见推送的消息

http://192.168.0.110:9501?msg=hello

6、测试结果,这里输入什么就给返回什么,在项目中根据自己项目做fid与用户的关联即可。

阅读全文

Elasticsearch入门 搜索引擎
发表于 2016-8-11 | 浏览(1139) | PHP

Elasticsearch最高效开源的搜索引擎框架,我们下面添加几条员工数据进行演示,详情可以在线文档查看,这里用PHP操作Elasticsearch的一些例子,在使用例子的情况下需要先安装Elasticsearch搜索引擎,安装方法可以查看官网,地址:https://www.elastic.co/downloads/elasticsearch

Elasticsearch依赖java,地址:http://www.java.com/

中文文档地址:http://es.xiaoleilu.com/

公共方法,用于操作Elasticsearch

/**
 * [PostCurl post请求]
 * @param  [string]  $url    [请求地址]
 * @param  [string]  $option [参数]
 * @param  [integer] $header [http头部信息]
 * @param  [string]  $type   [请求类型]
 * @return [array]           [返回的数据]
 */
function PostCurl($url, $option = '', $header = '', $type = 'POST')
{
	if(empty($header)) $header = array();
    $curl = curl_init (); // 启动一个CURL会话
    curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); // 对认证证书来源的检查
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); // 从证书中检查SSL加密算法是否存在
    curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)'); // 模拟用户使用的浏览器
    if (! empty($option)) {
        if($type == 'PUT')
        {
            $options = json_encode($option);
        } else {
            $options = json_encode($option, JSON_FORCE_OBJECT);
        }
        curl_setopt($curl, CURLOPT_POSTFIELDS, $options); // Post提交的数据包
    }
    curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header); // 设置HTTP头
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $type);
    $result = curl_exec($curl); // 执行操作
    curl_close($curl); // 关闭CURL会话
    return json_decode($result, true);
}

定义url地址

$url = 'http://localhost:9200/';

1、添加员工数据

关系数据库     ⇒ 数据库 ⇒ 表     ⇒ 行     ⇒ 列(Columns)

Elasticsearch   ⇒ 索引   ⇒ 类型   ⇒ 文档   ⇒ 字段(Fields)

索引 megacorp

类型 employee

文档 1 ~ 3

字段

// 定义员工数据
$param = array(
	1	=>	array(
			'first_name'	=>	'John',
			'last_name'		=>	'Smith',
			'age'			=>	25,
			'about'			=>	'I love to go rock climbing',
			'interests'		=>	array('sports', 'music')
		),
	2	=>	array(
			'first_name'	=>	'Jane',
			'last_name'		=>	'Smith',
			'age'			=>	32,
			'about'			=>	'I like to collect rock albums',
			'interests'		=>	array('music')
		),
	3	=>	array(
			'first_name'	=>	'Douglas',
			'last_name'		=>	'Fir',
			'age'			=>	35,
			'about'			=>	'I like to build cabinets',
			'interests'		=>	array('forestry')
		),
	);


// 循环将员工数据加入 Elasticsearch 搜索引擎中
$success = 0;
foreach($param as $k=>$v)
{
	$result = PostCurl($url.'megacorp/employee/'.$k, $v, '', 'PUT');
	if(isset($result['_shards']['successful']) && $result['_shards']['successful'] == 1) $success++;
}
echo $success.'<br />';


输出 3

2、获取id为1的员工数据

$result = PostCurl($url.'megacorp/employee/1', '', '', 'GET');
print_r($result);

返回数据
Array
(
    [_index] => megacorp
    [_type] => employee
    [_id] => 1
    [_version] => 28
    [found] => 1
    [_source] => Array
        (
            [first_name] => John
            [last_name] => Smith
            [age] => 25
            [about] => I love to go rock climbing
            [interests] => Array
                (
                    [0] => sports
                    [1] => music
                )

        )

)

3、搜索全部员工

$result = PostCurl($url.'megacorp/employee/_search', '', '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 4
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 3
            [max_score] => 1
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                    [2] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 3
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => Douglas
                                    [last_name] => Fir
                                    [age] => 35
                                    [about] => I like to build cabinets
                                    [interests] => Array
                                        (
                                            [0] => forestry
                                        )

                                )

                        )

                )

        )

)

4、搜索姓 last_name等于Smith的员工, 轻量的搜索方法

$result = PostCurl($url.'megacorp/employee/_search?q=last_name:Smith', '', '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 6
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 2
            [max_score] => 0.30685282
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                )

        )

)

5、使用Query DSL搜索。搜索姓 last_name等于Smith的员工, 轻量的搜索方法

$param = array(
	'query'	=>	array(
			'match'	=>	array('last_name'	=>	'Smith'),
		),
	);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 1
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 2
            [max_score] => 0.30685282
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                )

        )

)

6、更加复杂的搜索,搜索姓 last_name等于Smith的员工, 轻量的搜索方法。年龄大于30岁的限定条

$param = array(
	'query'	=>	array(
		'filtered'	=>	array(
			'query'		=>	array(
				'match'	=>	array('last_name'	=>	'Smith'),
			),

			'filter'	=>	array(
				'range'	=>	array(
					'age'	=>	array('gt'	=>	30)
				),
			),
		),
	),
);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 4
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 1
            [max_score] => 0.30685282
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                )

        )

)

7、更加复杂的全文搜索。一项在传统数据库很难实现的功能、我们将会搜索所有喜欢 rock climbing 的员工

$param = array(
	'query'	=>	array(
			'match'	=>	array('about'	=>	'rock climbing'),
		),
	);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 7
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 2
            [max_score] => 0.16273327
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 0.16273327
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 0.016878016
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                )

        )

)

8、段落搜索。我们只需要查询到 about 字段只包含 rock climbing 的短语的员工

$param = array(
	'query'	=>	array(
			'match_phrase'	=>	array('about'	=>	'rock climbing'),
		),
	);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 2
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 1
            [max_score] => 0.23013961
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 0.23013961
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                )

        )

)

9、高亮我们的搜索。但是添加一个 highlight 参数

$param = array(
	'query'	=>	array(
			'match_phrase'	=>	array('about'	=>	'rock climbing'),
		),
	'highlight'	=>	array(
			'fields'	=>	array(
					'about'	=>	array()
				)
		),
	);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 2
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 1
            [max_score] => 0.23013961
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 0.23013961
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                            [highlight] => Array
                                (
                                    [about] => Array
                                        (
                                            [0] => I love to go rock climbing
                                        )

                                )

                        )

                )

        )

)

10、统计。例如,找一下员工中最受欢迎的兴趣是什么

$param = array(
	'aggs'	=>	array(
		'all_interests'	=>	array(
			'terms'	=>	array('field'	=>	'interests'),
		),
	),
);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 2
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 3
            [max_score] => 1
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                    [2] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 3
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => Douglas
                                    [last_name] => Fir
                                    [age] => 35
                                    [about] => I like to build cabinets
                                    [interests] => Array
                                        (
                                            [0] => forestry
                                        )

                                )

                        )

                )

        )

    [aggregations] => Array
        (
            [all_interests] => Array
                (
                    [doc_count_error_upper_bound] => 0
                    [sum_other_doc_count] => 0
                    [buckets] => Array
                        (
                            [0] => Array
                                (
                                    [key] => music
                                    [doc_count] => 2
                                )

                            [1] => Array
                                (
                                    [key] => forestry
                                    [doc_count] => 1
                                )

                            [2] => Array
                                (
                                    [key] => sports
                                    [doc_count] => 1
                                )

                        )

                )

        )

)

11、如果只想要查询姓 smith 的员工的兴趣汇总情况

$param = array(
	'query'	=>	array(
		'match'	=>	array(
			'last_name'	=>	'smith'
		),
	),
	'aggs'	=>	array(
		'all_interests'	=>	array(
			'terms'	=>	array('field'	=>	'interests'),
		),
	),
);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 2
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 2
            [max_score] => 0.30685282
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 0.30685282
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                )

        )

    [aggregations] => Array
        (
            [all_interests] => Array
                (
                    [doc_count_error_upper_bound] => 0
                    [sum_other_doc_count] => 0
                    [buckets] => Array
                        (
                            [0] => Array
                                (
                                    [key] => music
                                    [doc_count] => 2
                                )

                            [1] => Array
                                (
                                    [key] => sports
                                    [doc_count] => 1
                                )

                        )

                )

        )

)

12、汇总还允许多个层面的统计。比如我们还可以统计每一个兴趣下的平均年龄

$param = array(
	'aggs'	=>	array(
		'all_interests'	=>	array(
			'terms'	=>	array('field'	=>	'interests'),
			'aggs'	=>	array(
				'avg_age' =>	array(
					'avg'	=>	array(
						'field'	=>	'age'
					),
				),
			),
		),
	),
);
$result = PostCurl($url.'megacorp/employee/_search', $param, '', 'GET');
print_r($result);

返回数据
Array
(
    [took] => 16
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 3
            [max_score] => 1
            [hits] => Array
                (
                    [0] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 2
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => Jane
                                    [last_name] => Smith
                                    [age] => 32
                                    [about] => I like to collect rock albums
                                    [interests] => Array
                                        (
                                            [0] => music
                                        )

                                )

                        )

                    [1] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 1
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => John
                                    [last_name] => Smith
                                    [age] => 25
                                    [about] => I love to go rock climbing
                                    [interests] => Array
                                        (
                                            [0] => sports
                                            [1] => music
                                        )

                                )

                        )

                    [2] => Array
                        (
                            [_index] => megacorp
                            [_type] => employee
                            [_id] => 3
                            [_score] => 1
                            [_source] => Array
                                (
                                    [first_name] => Douglas
                                    [last_name] => Fir
                                    [age] => 35
                                    [about] => I like to build cabinets
                                    [interests] => Array
                                        (
                                            [0] => forestry
                                        )

                                )

                        )

                )

        )

    [aggregations] => Array
        (
            [all_interests] => Array
                (
                    [doc_count_error_upper_bound] => 0
                    [sum_other_doc_count] => 0
                    [buckets] => Array
                        (
                            [0] => Array
                                (
                                    [key] => music
                                    [doc_count] => 2
                                    [avg_age] => Array
                                        (
                                            [value] => 28.5
                                        )

                                )

                            [1] => Array
                                (
                                    [key] => forestry
                                    [doc_count] => 1
                                    [avg_age] => Array
                                        (
                                            [value] => 35
                                        )

                                )

                            [2] => Array
                                (
                                    [key] => sports
                                    [doc_count] => 1
                                    [avg_age] => Array
                                        (
                                            [value] => 25
                                        )

                                )

                        )

                )

        )

)

删除指定日期之前的数据

curl -XDELETE 'http://localhost:9200/logstash-2017.02.25*'

上面这些已经可以基本掌握Elasticsearch的操作,后面更深入的、分布式集群,等...... 敬请关注~

阅读全文

PHP中4种排序算法
发表于 2016-7-6 | 浏览(811) | PHP
<?php

/**
 * PHP排序算法Demo
 */

/**
 * [bubble_sort 冒泡排序]
 * @param  [array] $data [需要排序的数据(相邻的数据进行比较调换位置)]
 * @return [array]       [排序好的数据]
 */
function bubble_sort($data)
{
	if(!empty($data) && is_array($data))
	{
		$len = count($data);
		for($i=0; $i<$len; $i++)
		{
			for($k=0; $k<$len-1; $k++)
			{
				if($data[$k] > $data[$i])
				{
					$data[$i] = $data[$i] ^ $data[$k];
					$data[$k] = $data[$i] ^ $data[$k];
					$data[$i] = $data[$i] ^ $data[$k];
				}
			}
		}
	}
	return $data;
}

/**
 * [select_sort 选择排序]
 * @param  [array] $data [需要排序的数据(选择最小的值与第一个调换位置)]
 * @return [array]       [排序好的数据]
 */
function select_sort($data)
{
	if(!empty($data) && is_array($data))
	{
		$len = count($data);
		for($i=0; $i<$len; $i++)
		{
			$t = $i;
			for($j=$i+1; $j<$len; $j++)
			{
				if($data[$t] > $data[$j])
				{
					$t = $j;
				}
			}
			if($t != $i)
			{
				$data[$i] = $data[$i] ^ $data[$t];
				$data[$t] = $data[$i] ^ $data[$t];
				$data[$i] = $data[$i] ^ $data[$t];
			}
		}
	}
	return $data;
}

/**
 * [insert_sort 插入排序]
 * @param  [array] $data [需要排序的数据(把第n个数插到前面的有序数组中,以此反复循环直到排序好)]
 * @return [array]       [排序好的数据]
 */
function insert_sort($data)
{
	if(!empty($data) && is_array($data))
	{
		$len = count($data);
		for($i=1; $i<$len; $i++)
		{
			$tmp = $data[$i];
			for($j=$i-1; $j>=0; $j--)
			{
				if($data[$j] > $tmp)
				{
					$data[$j+1] = $data[$j];
					$data[$j] 	= $tmp;
				} else {
					break;
				}
			}
		}
	}
	return $data;
}

/**
 * [quick_sort 快速排序]
 * @param  [array] $data [需要排序的数据(选择一个基准元素,将待排序分成小和打两罐部分,以此类推递归的排序划分两罐部分)]
 * @return [array]       [排序好的数据]
 */
function quick_sort($data)
{
	if(!empty($data) && is_array($data))
	{
		$len = count($data);
		if($len <= 1) return $data;

		$base = $data[0];
		$left_array = array();
		$right_array = array();
		for($i=1; $i<$len; $i++)
		{
			if($base > $data[$i])
			{
				$left_array[] = $data[$i];
			} else {
				$right_array[] = $data[$i];
			}
		}
		if(!empty($left_array)) $left_array = quick_sort($left_array);
		if(!empty($right_array)) $right_array = quick_sort($right_array);

		return array_merge($left_array, array($base), $right_array);
	}
}


/**
 * 测试
 */
$data = array(10, 3, 6, 1, 24, 18, 7, 8);
echo '<pre>';

// 冒泡排序
print_r(bubble_sort($data));

// 选择排序
print_r(select_sort($data));

// 插入排序
print_r(insert_sort($data));

// 快速排序
print_r(quick_sort($data));


// 以下是结果
Array
(
    [0] => 1
    [1] => 3
    [2] => 6
    [3] => 7
    [4] => 8
    [5] => 10
    [6] => 18
    [7] => 24
)
Array
(
    [0] => 1
    [1] => 3
    [2] => 6
    [3] => 7
    [4] => 8
    [5] => 10
    [6] => 18
    [7] => 24
)
Array
(
    [0] => 1
    [1] => 3
    [2] => 6
    [3] => 7
    [4] => 8
    [5] => 10
    [6] => 18
    [7] => 24
)
Array
(
    [0] => 1
    [1] => 3
    [2] => 6
    [3] => 7
    [4] => 8
    [5] => 10
    [6] => 18
    [7] => 24
)

?>

阅读全文

PHP坐标圆周率计算
发表于 2016-6-16 | 浏览(732) | PHP
/**
 * [GetSquarePoint 坐标圆周率计算]
 *  $lng = '116.655540';
 *  $lat = '39.910980';
 *  $squares = GetSquarePoint($lng, $lat);
 *       
 *  print_r($squares);
 *  $info_sql = "select id,locateinfo,lat,lng from `lbs_info` where lat<>0 and lat>{$squares['right-bottom']['lat']} and lat<{$squares['left-top']['lat']} and lng>{$squares['left-top']['lng']} and lng<{$squares['right-bottom']['lng']} ";
 *  计算某个经纬度的周围某段距离的正方形的四个点
 *
 *  param lng float 经度
 *  param lat float 纬度
 *  param distance float 该点所在圆的半径,该圆与此正方形内切,默认值为0.5千米
 *  return array 正方形的四个点的经纬度坐标
 */
function GetSquarePoint($lng, $lat, $distance = 0.5)
{
	if(empty($lng) || empty($lat)) return '';

    /* 地球半径,平均半径为6371km */
    $radius = 6371;

    $d_lng =  2 * asin(sin($distance / (2 * $radius)) / cos(deg2rad($lat)));
    $d_lng = rad2deg($d_lng);

    $d_lat = $distance/$radius;
    $d_lat = rad2deg($d_lat);

    return array(
        'left-top'=>array('lat'=>$lat + $d_lat,'lng'=>$lng-$d_lng),
        'right-top'=>array('lat'=>$lat + $d_lat, 'lng'=>$lng + $d_lng),
        'left-bottom'=>array('lat'=>$lat - $d_lat, 'lng'=>$lng - $d_lng),
        'right-bottom'=>array('lat'=>$lat - $d_lat, 'lng'=>$lng + $d_lng)
    );
}

阅读全文

PHP TCP通信
发表于 2016-6-15 | 浏览(909) | PHP

创建文件 server.php 内容如下

<?php

$filename = '/data/www/devil/tcp/server.txt';
$myfile = fopen($filename, "a+");
set_time_limit( 0 );
ob_implicit_flush();
$socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
socket_bind( $socket, '192.168.1.94', 11109 );
socket_listen($socket);
$acpt=socket_accept($socket);
echo "Acpt!\n";
while ( $acpt ) {
    $words=fgets(STDIN);
    socket_write($acpt,$words);
    $hear=socket_read($acpt,1024);
    echo $hear;
    fwrite($myfile, $hear);
    if("bye\r\n"==$hear){
        socket_shutdown($acpt);
        break;
    }
    usleep( 5000 );
}
socket_close($socket);

fclose($myfile);
?>

创建文件 client.php 内容如下

<?php

$filename = '/data/www/devil/tcp/client.txt';
$myfile = fopen($filename, "a+");

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$con=socket_connect($socket,'192.168.1.94',11109);
if(!$con){socket_close($socket);exit;}
echo "Link\n";
while($con){
        $hear=socket_read($socket,1024);
        echo $hear;
        fwrite($myfile, $hear);
        $words=fgets(STDIN);
        socket_write($socket,$words);
        if($words=="bye\r\n"){break;}
        usleep( 5000 );
}
socket_shutdown($socket);
socket_close($sock);

fclose($myfile);
?>

文件创建好后,修改 $filename 变量相对应自己系统的地址,写测试数据

192.168.1.94 ip改成自己服务器的或者本机ip

php server.php
php client.php

在 server.php 窗口输入 hello
回到 client.php 窗口可以马上看见 hello
当然在 client.php 窗口输入的内容在 server.php 窗口也可以马上看见

阅读全文

PHP计算两个坐标之间的距离
发表于 2016-6-15 | 浏览(775) | PHP
/**
 * [GetDistance 计算两个进纬度之间的距离]
 * @param [float] $lat1 [纬度1]
 * @param [float] $lng1 [经度1]
 * @param [float] $lat2 [纬度2]
 * @param [float] $lng2 [经度2]
 * @return[float]       [两个坐标距离值]
 */
function GetDistance($lat1, $lng1, $lat2, $lng2)
{
    $pi = 3.1415926535898;
    $earth_radius = 6378.137;

    $radLat1 = $lat1 * ($pi / 180);
    $radLat2 = $lat2 * ($pi / 180);
   
    $a = $radLat1 - $radLat2; 
    $b = ($lng1 * ($pi / 180)) - ($lng2 * ($pi / 180)); 
   
    $s = 2 * asin(sqrt(pow(sin($a/2),2) + cos($radLat1)*cos($radLat2)*pow(sin($b/2),2))); 
    $s = $s * $earth_radius; 
    $s = round($s * 10000) / 10000; 
    return $s; 
}

阅读全文

PHP图片上传(简约版)
发表于 2016-5-5 | 浏览(1023) | PHP
<?php

/**
 * 图片处理类
 * @author  Devil
 * @version v_0.0.1
 */
class Images
{
	private $path;
	private $zoom;

	/**
	 * [__construct 构造方法]
	 * @param [string]  $path [图片存储路径]
	 * @param [int]	 	$zoom [压缩程度]
	 */
	public function __construct($path = '', $zoom = 60)
	{
		// 参数校验
		if(empty($path)) exit('param path no');

		// 属性赋值
		$this->path = $path;
		$this->zoom = $zoom;
	}

	/**
	 * [ImagesReturn 数据返回]
	 * @param [mixed]  	$msg  [错误信息/数据]
	 * @param [int] 	$code [状态]
	 * @return[array]         [返回数据]
	 */
	private function ImagesReturn($msg = '', $code = 0)
	{
		return array('msg'=>$msg, 'code'=>$code);
	}

	/**
	 * [FormSave form图片资源存储]
	 * @param [string] $resources 	[图片临时资源]
	 * @param [string] 	$name   	[图片名称(可空)]
	 * @param [string] 	$path   	[自定义图片路径(可空)]
	 * @return[array]               [图片名称]
	 */
	public function FormSave($resources, $name = '', $path = '')
	{
		// 参数校验
		if(empty($resources['tmp_name']) || empty($resources['type'])) return $this->ImagesReturn('参数错误', -1);

		// 文件名生成
		$file_name = empty($name) ? $this->FileNewName() : $name;

		// 图片后缀名
		$suffix = $this->GetSuffix($resources['type']);
		if(empty($suffix)) $this->ImagesReturn('图片后缀名有误', -2);

		// 图片存储
		$file_name = $file_name.'.'.$suffix;
		$path = empty($path) ? $this->path : $path;
		if(move_uploaded_file($resources['tmp_name'], $path.$file_name)) return $this->ImagesReturn($file_name);

		// 返回错误
		return $this->ImagesReturn('图片存储失败', -100);
	}

	/**
	 * [GetSuffix 获取图片的后缀名]
	 * @param [string] $type [图片资源类型]
	 * @return[string]       [后缀名]
	 */
	private function GetSuffix($type)
	{
		$img_all = array(
			'jpg' => 'image/jpeg',
			'png' => 'image/png',
			'gif' => 'image/gif');

		$key = array_search($type, $img_all);
		if($key === false) return '';
		return $key;
	}

	/**
	 * [FileNewName 生成文件名]
	 */
	private function FileNewName()
	{
		$name = date('YmdHis');
		for($i=0; $i<6; $i++) $name .= rand(0, 9);
		return $name;
	}

	/**
	 * [Compression 图片缩放存储]
	 * @param [string]  $images [图片资源]
	 * @param [string] 	$name   [图片名称(可空)]
	 * @param [string] 	$path   [自定义图片路径(可空)]
	 * @param [int] 	$w      [宽度(可空)]
	 * @param [int] 	$h      [高度(默认原始尺寸或以宽度自动计算)]
	 * @param [int] 	$zoom   [压缩值(默认60)]
	 * @return[array] 			[图片信息]
	 */
	public function Compression($images, $name = '', $path = '', $w = 0, $h = 0, $zoom = 0)
	{
		// 参数校验
		if(empty($images)) return $this->ImagesReturn('参数错误', -1);

		// 获取图片信息
		$info = @getimagesize($images);
		if($info == false) return $this->ImagesReturn('图片有误', -2);

		// 文件名生成
		$file_name = empty($name) ? $this->FileNewName() : $name;

		// 图片后缀名
		//$suffix = $this->GetSuffix($info['mime']);
		$suffix = strrchr($images, '.'); 
		if(empty($suffix)) return $this->ImagesReturn('图片后缀名有误', -3);
		
		// 取得尺寸的比例值
		$proportion = empty($w) ? 0 : $w/$info[0];

		// 新的宽度
		$new_width = empty($w) ? $info[0] : $w;

		// 如果没有自定义高度则根据宽度计算高度
		$new_height = empty($h) ? (($w < $info[0] && !empty($proportion)) ? intval($proportion*$info[1]) : (($w > $info[0] && !empty($proportion)) ? intval($proportion*$info[1]) : $info[1])) : $h;

		// 新建一个彩色图像
		$new_img = imagecreatetruecolor($new_width, $new_height);

		// 图片资源
		$img = $this->ImageFrom($images, $new_img, $info['mime']);
		if(!$img) return $this->ImagesReturn('图片资源获取失败', -4);

		// 缩放图片
		imagecopyresampled($new_img, $img, 0, 0, 0, 0, $new_width, $new_height, $info[0], $info[1]);

		// 缩放程度
		$zoom = empty($zoom) ? (empty($this->zoom) ? 100 : $this->zoom) : $zoom;

		// 存储图片
		$file_name = $file_name.$suffix;
		$path = empty($path) ? $this->path : $path;
		switch($info['mime'])
		{
			case 'image/png':
				$state = imagepng($new_img, $path.$file_name);
				break;

			case 'image/gif':
				$state = imagegif($new_img, $path.$file_name);
				break;

			default:
				$state = imagejpeg($new_img, $path.$file_name, $zoom);
		}

		// 释放内容
		imagedestroy($img);
		imagedestroy($new_img);

		// 返回
		if($state) return $this->ImagesReturn($file_name);
		return $this->ImagesReturn($file_name);
		$this->ImagesReturn('文件储存失败', -100);
	}

	/**
	 * [ImageFrom 图片资源获取]
	 * @param [string] $images [原图片资源]
	 * @param [string] $new_img[新的图片资源]
	 * @param [string] $type   [图片类型]
	 * @return[mixed]          [成功返回图象资源,失败返回 false]
	 */
	private function ImageFrom($images, $new_img, $type)
	{
		// 参数校验
		if(empty($images) || empty($type)) return false;

		// 图片资源获取
		switch($type)
		{
			case 'image/png':
				$img = imagecreatefrompng($images);

				// png保留透明背景
				imagealphablending($new_img, false);
				imagesavealpha($new_img, true);
				imagesavealpha($img, true);
				break;

			case 'image/gif':
				$img = imagecreatefromgif($images);
				break;

			default:
				case 'image/jpeg':
				$img = imagecreatefromjpeg($images);
		}
		return $img;
	}
}
?>

阅读全文

PHP图片验证码生成
发表于 2016-5-5 | 浏览(614) | PHP
<?php

/**
 * 验证码驱动
 * @author  Devil
 * @version v_1.0.0
 */
class VerifyLibrary
{
	private $rand_string;
	private $img;

	/**
	 * [__construct 构造方法]
	 */
	public function __construct()
	{
		/* 验证码生成 */
		$this->rand_string = $this->GetRandString();
	}

	/**
	 * [GetVerify 获取当前验证码]
	 */
	public function GetVerify()
	{
		return $this->rand_string;
	}

	/**
	 * [GetVerifyImg 验证码生成]
	 * @return [string] [验证码]
	 */
	public function GetVerifyImg() {
		$this->img = imagecreatetruecolor(63, 22); //创建一个画布(真色彩)

		// 画背景
		$back_color = imagecolorallocate($this->img, 235, 236, 237); 
        imagefilledrectangle($this->img,0,0,63,22,$back_color);

		//加入干扰,画出多条线
		$this->InterferenceLine();
		
		//加入干扰,画出点    
		$this->InterferencePoint();

		//将生成好的字符串写入图像
		$fgcolor = imagecolorallocate($this->img, rand(0,200), rand(0,255), rand(0,255));
		imagestring($this->img, 5, 5, 5, strtoupper($this->rand_string), $fgcolor);

		//输出图像
		header('Content-Type: image/gif');
		imagegif($this->img);

		//销毁图像
		imagedestroy($this->img);
	}

	/**
	 * [InterferencePoint 加入干扰,画点]
	 */
	private function InterferencePoint()
	{
		for($i=0; $i<200; $i++){ 
			$bgcolor = imagecolorallocate($this->img, rand(0,255), rand(0,255), rand(0,255));  //产生随机的颜色
			imagesetpixel($this->img, rand()%90, rand()%30, $bgcolor); 
		}
	}

	/**
	 * [InterferenceLine 加入干扰,画出多条线]
	 */
	private function InterferenceLine()
	{
		for($i=0; $i<5; $i++)
		{
			$bgcolor=imagecolorallocate($this->img, rand(0,255), rand(0,255), rand(0,255));  //产生随机的颜色
			imageline($this->img, rand(10,90), 0, rand(10,90), 20, $bgcolor);
		}
	}

	/**
	 * [GetRandString 生成随机数值]
	 * @param [int] 	$number [随机数位数]
	 * @return[string] 			[返回小写的随机数值]
	 */
	private function GetRandString($number = 6)
	{
		$origstr = '3456789abxdefghijkmnprstuvwxy';
		$verifystring = '';
		$len = strlen($origstr);
		for($i=0; $i<$number; $i++) {
			$index = mt_rand(0, $len-1);
			$char = $origstr[$index];
			$verifystring .= $char;
		}
		return $verifystring;
	}

}
?>

阅读全文

微信支付接口,服务器端处理(新版)
发表于 2016-4-12 | 浏览(2812) | PHP
<?php

/**
 * 微信支付驱动
 * @author  Devil
 * @version V_1.0.0
 */
class WeiXinPay
{
    private $appid;
    private $secret;
    private $mch_id;
    private $key;

    /**
     * [__construct 构造方法]
     */
    private function __construct($config)
    {
        $this->appid = isset($config['appid']) ? $config['appid'] : '';
        $this->secret = isset($config['secret']) ? $config['secret'] : '';
        $this->mch_id = isset($config['mchid']) ? $config['mchid'] : '';
        $this->key = isset($config['key']) ? $config['key'] : '';
    }

    /**
     * [Instantiate 静态方法]
     * @param [array] $config   [微信配置信息]
     * @return[object]          [当前类对象]
     */
    public static function Instantiate($config)
    {
        $object = null;
        if(!is_object($object)) $object = new self($config);
        return $object;
    }

    /**
     * [WechatPay 微信支付]
     * @param [string]  $param['body']              [商品简要描述]
     * @param [string]  $param['out_trade_no']      [商户订单号]
     * @param [int]     $param['total_fee']         [订单总金额]
     * @param [string]  $param['notify_url']        [异步通知地址]
     * @param [string]  $param['trade_type']        [交易类型(默认JSAPI)JSAPI | APP]
     * @param [string]  $param['openid']            [openid]
     * @param [string]  $param['attach']            [原样返回的数据(可选)]
     * @return[array]                                  [微信支付数据]
     */
    public function WechatPay($param)
    {
        if(empty($param)) return '';

        $data = $this->GetPayParam($param);

        $xml = '<xml>
                <appid>'.$this->appid.'</appid>
                <body>'.$data['data']['body'].'</body>
                <mch_id>'.$this->mch_id.'</mch_id>
                <nonce_str>'.$data['data']['nonce_str'].'</nonce_str>
                <notify_url>'.$data['data']['notify_url'].'</notify_url>
                <openid>'.$data['data']['openid'].'</openid>
                <out_trade_no>'.$data['data']['out_trade_no'].'</out_trade_no>
                <spbill_create_ip>'.$data['data']['spbill_create_ip'].'</spbill_create_ip>
                <total_fee>'.$data['data']['total_fee'].'</total_fee>
                <trade_type>'.$data['data']['trade_type'].'</trade_type>
                <attach>'.$data['data']['attach'].'</attach>
                <sign>'.$data['sign'].'</sign>
            </xml>';

        $result = $this->Xml_Array($this->Curl_Post('https://api.mch.weixin.qq.com/pay/unifiedorder', $xml));
        if(!empty($result['prepay_id']))
        {
            // 返回数据
            $pay_data = array(
                    'appid'         =>  $this->appid,
                    'partnerid'     =>  $this->mch_id,
                    'prepayid'      =>  $result['prepay_id'],
                    'package'       =>  'Sign=WXPay',
                    'noncestr'      =>  md5(time().rand()),
                    'timestamp'     =>  time(),
                );
            $pay_data['sign'] = $this->GetParamSing($pay_data);
            return $pay_data;
        }
        return '';
    }

    /**
     * [Refund 退款接口]
     * @param   [array] $param  [退款的参数]
     * @return  [boolean]       [成功true, 则false]
     */
    public function Refund($param)
    {
        if(empty($param)) return false;

        $data = array(
                'appid'         =>  $this->appid,
                'mch_id'        =>  $this->mch_id,
                'nonce_str'     =>  md5(time().rand()),
                'transaction_id'=>  $param['transaction_id'],
                'out_refund_no' =>  md5($param['transaction_id'].$param['total_fee']),
                'total_fee'     =>  $param['total_fee'],
                'refund_fee'    =>  $param['refund_fee'],
                'op_user_id'    =>  $this->mch_id,
            );
        $data['sign'] = $this->GetParamSing($data);

        $result = $this->Xml_Array($this->Curl_Post('https://api.mch.weixin.qq.com/secapi/pay/refund', $this->GetParamXml($data), true));
        return (!empty($result['result_code']) && $result['result_code'] == 'SUCCESS' && !empty($result['return_msg']) && $result['return_msg'] == 'OK');
    }

    /**
     * [GetParamXml xml键值对拼接]
     * @param [array] $param [需要拼接xml的数组]
     * @return[string]       [xml数据]
     */
    private function GetParamXml($param)
    {
        if(empty($param) || !is_array($param)) return '';

        $xml = '';
        foreach($param as $k=>$v)
        {
            $xml .= '<'.$k.'>'.$v.'</'.$k.'>';
        }
        return '<xml>'.$xml.'</xml>';
    }

    /**
     * [Xml_Array xml转数组]
     * @param [string] $xml [xml字符串]
     * @return[array]       [数组]
     */
    private function Xml_Array($xml)
    {
        if(!Xml_Parser($xml)) return '';

        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    /**
     * [GetPayParam 获取支付参数]
     * @param [array] $param [支付的数据]
     * @return[array] [支付的字符串和签名]
     */
    private function GetPayParam($param)
    {
        if(empty($param)) return '';

        $param['appid'] = $this->appid;
        $param['mch_id'] = $this->mch_id;
        $param['nonce_str'] = md5(time().rand().$param['out_trade_no']);
        $param['spbill_create_ip'] = get_client_ip();
        $param['trade_type'] = empty($param['trade_type']) ? 'JSAPI' : $param['trade_type'];
        $param['attach'] = empty($param['attach']) ? 'gongfuxiang' : $param['attach'];
        return array(
            'sign'  =>  $this->GetParamSing($param),
            'data'  =>  $param,
        );
    }

    /**
     * [GetParamSing 签名生成]
     * @param [array] $param    [需要参与签名的数据]
     * @return[string]          [签名]
     */
    private function GetParamSing($param)
    {
        if(empty($param)) return '';

        ksort($param);
        $sign  = '';
        foreach($param as $k=>$v)
        {
            if($k != 'sign') $sign .= "$k=$v&";
        }
        return strtoupper(md5($sign.'key='.$this->key));
    }

    /**
     * [Curl_Post curl模拟post]
     * @param  [string] $url        [请求地址]
     * @param  [array] $post        [发送的post数据]
     * @param  [boolean] $use_cert  [是否需要使用证书]
     */
    private function Curl_Post($url, $post, $use_cert = false)
    {
        $options = array(
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER         => false,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $post,
        );

        if($use_cert == true)
        {
            //设置证书
            //使用证书:cert 与 key 分别属于两个.pem文件
            $options[CURLOPT_SSLCERTTYPE] = 'PEM';
            $options[CURLOPT_SSLCERT] = WEB_ROOT.'cert/wechat_app_apiclient_cert.pem';
            $options[CURLOPT_SSLKEYTYPE] = 'PEM';
            $options[CURLOPT_SSLKEY] = WEB_ROOT.'cert/wechat_app_apiclient_key.pem';
        }
 
        $ch = curl_init($url);
        curl_setopt_array($ch, $options);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    /**
     * [Notify 异步回调]
     * @return [array] [支付数据]
     */
    public function Notify()
    {
        $result = empty($GLOBALS['HTTP_RAW_POST_DATA']) ? '' : $this->Xml_Array($GLOBALS['HTTP_RAW_POST_DATA']);

        if(isset($result['sign']) && $result['sign'] == $this->GetParamSing($result)) return $result;
        return '';
    }
}
?>

阅读全文

微信公众号支付
发表于 2016-1-25 | 浏览(1053) | PHP
<?php

/**
 * 微信支付驱动
 * @author  Devil
 * @version V_1.0.0
 */
class WechatPayLibrary
{
    private $appid;
    private $secret;
    private $mch_id;
    private $key;

    /**
     * [__construct 构造方法]
     */
    private function __construct($config)
    {
        $this->appid = isset($config['appid']) ? $config['appid'] : '';
        $this->secret = isset($config['secret']) ? $config['secret'] : '';
        $this->mch_id = isset($config['mchid']) ? $config['mchid'] : '';
        $this->key = isset($config['key']) ? $config['key'] : '';
    }

    /**
     * [Instantiate 静态方法]
     * @param [array] $config   [微信配置信息]
     * @return[object]          [当前类对象]
     */
    public static function Instantiate($config)
    {
        $object = null;
        if(!is_object($object)) $object = new self($config);
        return $object;
    }

    /**
     * [WechatPay 微信支付]
     * @param [string] $param['body']           [商品简要描述]
     * @param [string] $param['out_trade_no']   [商户订单号]
     * @param [array] $param['total_fee']       [订单总金额]
     * @param [array] $param['notify_url']      [异步通知地址]
     * @param [array] $param['trade_type']      [交易JSAPI类型]
     * @return[array]                           [微信支付数据]
     */
    public function WechatPay($param)
    {
        if(empty($param)) return '';

        $data = $this->GetPayParam($param);

        $xml = '<xml>
                <appid>'.$this->appid.'</appid>
                <body>'.$data['data']['body'].'</body>
                <mch_id>'.$this->mch_id.'</mch_id>
                <nonce_str>'.$data['data']['nonce_str'].'</nonce_str>
                <notify_url>'.$data['data']['notify_url'].'</notify_url>
                <openid>'.$data['data']['openid'].'</openid>
                <out_trade_no>'.$data['data']['out_trade_no'].'</out_trade_no>
                <spbill_create_ip>'.$data['data']['spbill_create_ip'].'</spbill_create_ip>
                <total_fee>'.$data['data']['total_fee'].'</total_fee>
                <trade_type>'.$data['data']['trade_type'].'</trade_type>
                <sign>'.$data['sign'].'</sign>
            </xml>';

        $result = $this->Xml_Array($this->Curl_Post('https://api.mch.weixin.qq.com/pay/unifiedorder', $xml));
        if(!empty($result))
        {
            // 返回数据
            $pay_data = array(
                    'appId'         =>  $this->appid,
                    'timeStamp'     =>  time(),
                    'signType'      =>  'MD5',
                    'nonceStr'      =>  md5(time().rand()),
                    'package'       =>  'prepay_id='.$result['prepay_id'],
                );
            $pay_data['paySign'] = $this->GetParamSing($pay_data);

            return $pay_data;
        }
        return '';
    }

    /**
     * [Xml_Array xml转数组]
     * @param [string] $xml [xml字符串]
     * @return[array]       [数组]
     */
    private function Xml_Array($xml)
    {
        if(!Xml_Parser($xml)) return '';

        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    /**
     * [GetPayParam 获取支付参数]
     * @param [array] $param [支付的数据]
     * @return[array] [支付的字符串和签名]
     */
    private function GetPayParam($param)
    {
        if(empty($param)) return '';

        $param['appid'] = $this->appid;
        $param['mch_id'] = $this->mch_id;
        $param['nonce_str'] = md5(time().rand().$param['out_trade_no']);
        $param['spbill_create_ip'] = get_client_ip();
        $param['trade_type'] = 'JSAPI';
        return array(
            'sign'  =>  $this->GetParamSing($param),
            'data'  =>  $param,
        );
    }

    /**
     * [GetParamSing 签名生成]
     * @param [array] $param    [需要参与签名的数据]
     * @return[string]          [签名]
     */
    private function GetParamSing($param)
    {
        if(empty($param)) return '';

        ksort($param);
        $sign  = '';
        foreach($param as $k=>$v)
        {
            if($k != 'sign') $sign .= "$k=$v&";
        }
        return strtoupper(md5($sign.'key='.$this->key));
    }

    /**
     * [Curl_Post curl模拟post]
     * @param  [string] $url  [请求地址]
     * @param  [array] $post  [发送的post数据]
     */
    private function Curl_Post($url, $post)
    {
        $options = array(
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER         => false,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $post,
        );
 
        $ch = curl_init($url);
        curl_setopt_array($ch, $options);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    /**
     * [Notify 异步回调]
     * @return [array] [支付数据]
     */
    public function Notify()
    {
        $result = empty($GLOBALS['HTTP_RAW_POST_DATA']) ? '' : $this->Xml_Array($GLOBALS['HTTP_RAW_POST_DATA']);

        if(isset($result['sign']) && $result['sign'] == $this->GetParamSing($result)) return $result;
        return '';
    }
}
?>

阅读全文

TOP