使用的时候需要有pem证书,然后修改一下iosPush.php,即可使用
/**********************************************PHP脚本*****************************************************/
<?php
/**
* ios推送脚本,暂时没做分批次,先测试好再优化
* exec('php '.ROOT_PATH.'include/shell/iosPush.php -c '.$content.' -r 0 -a '.MEMBER_NAME);
* https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW15
*/
date_default_timezone_set('Asia/Shanghai');
define('DATABASE', 'database');
define('TABLE_PRE', 'table_pre_');
//证书位置
define('DOMAIN_ROOT_PATH', dirname(dirname(__DIR__)) . '/');
define('PEM_DIR', DOMAIN_ROOT_PATH . 'apns_product.pem');
//日志位置
define('TODAY', date('Y-m-d'));
define('LOG_FILE', DOMAIN_ROOT_PATH . '.log/' . TODAY . '.log');
//apn接口地址,两者其一即可--'https://api.push.apple.com:443/3/device/';
define('SERVICE_URL', 'https://api.push.apple.com/3/device/');
//bundle-id
define('BUNDLE_ID', 'com.test.abc');
set_time_limit(0);
ini_set('memory_limit', '-1');
ini_set('display_errors', 1);
//数据库
$config = array(
'defaultDb' => array(
'db_type' => 'mysql',
'db_host' => '127.0.0.1',//登陆地址
'db_user' => 'root',//登陆用户名
'db_pass' => 'root',//登陆密码
'db_name' => DATABASE,//用户数据库名字
'db_persist' => '0',
'db_port' => '3306',
)
);
$sql_link = '';
function myQuery($sql_link = '', $sql = '', $db_name = DATABASE)
{
if (!$sql_link || !mysqli_ping($sql_link) || $db_name) {
$config = $GLOBALS['config'];
$db = $config['defaultDb'];
$db['db_name'] = $db_name;
$GLOBALS['sql_link'] = $sql_link = @mysqli_connect($db['db_host'], $db['db_user'], $db['db_pass'],
$db['db_name'], $db['db_port']);
mysqli_query($sql_link, 'set names utf8');
}
if ($sql) {
return mysqli_query($sql_link, $sql);
}
}
//处理参数
$param_arr = getopt('c:r:a:');//p:content;r:rePush;a:操作的admin
$content = $param_arr['c'];
$administrator = $param_arr['a'];
$rePush = $param_arr['r'];
$title = $body = '';
if (strpos($content, '@@') !== false) {
$title = explode('@@', $content)[0];
$body = explode('@@', $content)[1];
} else {
$body = $content;
}
$params = array('title' => $title, 'body' => $body);
$massage['aps'] = array(
'alert' => $params,
'sound' => 'default',
'badge' => 1
);
$payload = json_encode($massage);
$requestUrl = array();
if($rePush == 1){
$sql = " select a.`uid`,a.`token` from " . TABLE_PRE . "member_push_token a LEFT JOIN " . TABLE_PRE . "member_push_log b on a.uid=b.uid where b.uid IS NULL";
}else{
$sql = "select `uid`,`token` from " . TABLE_PRE . "member_push_token";
}
$indexer = 0;
$res = myQuery($sql_link, $sql);
while ($value = mysqli_fetch_assoc($res)) {
$indexer++;
$requestUrl[$value['uid']] = SERVICE_URL.$value['token'];
if ($indexer % 100 == 0) {
multiPush($requestUrl);
$requestUrl = array();
sleep(3);
}
}
//剩下的未满100条,发送
if(!empty($requestUrl)){
multiPush($requestUrl);
$requestUrl = array();
}
/**
* @param $urls --格式array('uid'=>'url')
*/
function multiPush($urls){
global $sql_link;
global $content;
global $administrator;
global $payload;
$now = time();
$headers = array(
'apns-topic:' . BUNDLE_ID// bundle-id
);
//1、初始化一个批处理handle
$mh = curl_multi_init();
//2、往批处理handle 添加curl_init来的子handle
foreach ($urls as $i => $url) {
$conn[$i] = curl_init($url);
curl_setopt($conn[$i], CURLOPT_HTTP_VERSION, 3);
curl_setopt($conn[$i], CURLOPT_SSLCERT, PEM_DIR); // HTTP/2推送证书
curl_setopt($conn[$i], CURLOPT_SSLCERTPASSWD, '');// 证书没有密码
// curl_setopt($conn[$i], CURLOPT_URL, SERVICE_URL . $token);
curl_setopt($conn[$i], CURLOPT_HTTPHEADER, $headers);
curl_setopt($conn[$i], CURLOPT_POSTFIELDS, $payload);
// curl_setopt($conn[$i], CURLOPT_FRESH_CONNECT, 1); //TRUE 强制获取一个新的连接,而不是缓存中的连接。
curl_setopt($conn[$i], CURLOPT_TIMEOUT, 0);
// curl_setopt($conn[$i], CURLOPT_HEADER, true); // 显示response头
curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1);
curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT, 60);
curl_multi_add_handle($mh, $conn[$i]);
}
//3、并发执行,直到全部结束。
do {
curl_multi_exec($mh, $active);
} while ($active);
//4、获取结果
foreach ($urls as $i => $url) {
$return = curl_multi_getcontent($conn[$i]);
if ($return) {
$msg = json_decode($return, true)['reason'];
push_log($i . ' push failed: ' . $msg);
//token失效
if (in_array($msg, array('BadDeviceToken', 'DeviceTokenNotForTopic'))) {
$deleteSql = "delete from " . TABLE_PRE . "member_push_token where `uid` = '{$i}' ";
myQuery($sql_link, $deleteSql);
} else {
$sql = "insert into " . TABLE_PRE . "member_push_log VALUES (null,'{$administrator}','ios','{$i}','{$content}',0,'{$msg}',$now)";
myQuery($sql_link, $sql);
}
} else {
push_log($i . ' push success!');
$sql = "insert into " . TABLE_PRE . "member_push_log VALUES (null,'{$administrator}','ios','{$i}','{$content}',1,'',$now)";
myQuery($sql_link, $sql);
}
}
//5、移除子handle,并close子handle
foreach ($urls as $i => $url) {
curl_multi_remove_handle($mh,$conn[$i]);
curl_close($conn[$i]);
}
//6、关闭批处理handle
curl_multi_close($mh);
}
/**
* 日志记录
* @param string $content
*/
function push_log(string $content)
{
file_put_contents(LOG_FILE, date('Y-m-d H:i:s').'--'.$content . "\r\n", FILE_APPEND);
}
/**********************************************MySQL*****************************************************/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for member_push_log
-- ----------------------------
DROP TABLE IF EXISTS `member_push_log`;
CREATE TABLE `member_push_log` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`push_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '谁推送的',
`type` enum('android','ios') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'android,ios',
`uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户uid',
`content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推送内容',
`status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '1:成功;0失败',
`err_msg` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '错误原因',
`created_at` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
INDEX `uid`(`uid`) USING BTREE,
INDEX `push_by`(`push_by`(191)) USING BTREE,
INDEX `status`(`status`) USING BTREE,
INDEX `content`(`content`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'ios推送token' ROW_FORMAT = Compact;
-- ----------------------------
-- Table structure for member_push_token
-- ----------------------------
DROP TABLE IF EXISTS `member_push_token`;
CREATE TABLE `member_push_token` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户uid',
`token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '推送token',
`created_at` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uid`(`uid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'ios推送token' ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;