文以Gitee作为演示,Github实现步骤是一样的,区别在于二者WebHook推送的数据有所区别。
WebHook 功能是帮助用户 push 代码后,自动回调一个您设定的 http 地址。 这是一个通用的解决方案,用户可以自己根据不同的需求,来编写自己的相关程序。
服务器后台运行一个PHP cli 脚本,脚本运行时启动一个SSH客户端,然后再运行一个Redis客户端,Redis保持订阅,接收来自接口的Redis消息发布。
每当Redis接收到发布的推送消息,触发回调,通过SSH客户端执行Git命令。
PHP SSH 客户端
https://nicen.cn/2430.html
HTTP接口接收来自远程仓库的更新推送,然后把数据进行处理后推送给异步任务。
<?php
/* 获取推送的数据 */
$json = file_get_contents("php://input");
$data = json_decode($json, true);
/* 判断推送是否来自指定的用户 */
if ($data['user_name'] != "friend-nicen") {
exit("非法请求");
}
/* 处理数据 */
$need = [
"clone" => $data['repository']["clone_url"], //远程仓库地址
"path" => $data['repository']["path"], //远程仓库名
"branch" => str_replace("refs/heads/", '', $data['ref']) //分支
];
/*通过Redis订阅,进行任务投递*/
getRedis()->publish("RECV_GIT", json_encode($need));
exit("正在处理本次更新...");
使用前请先按照https://nicen.cn/2430.html,安装PHP拓展,您需要准备:
<?php
include_once 'vendor/autoload.php';
/* 引入SSH客户端 */
use phpseclib3\Net\SSH2;
/*
* 创建redis
* */
function getRedis():Redis
{
$redis = new Redis();
$redis->connect("IP","端口");
$redis->setOption(3, -1);
return $redis;
}
/*链接ssh*/
$ssh = new SSH2('localhost', 22);
/*如果登录失败*/
if (!$ssh->login('root', '您的SSH密码')) {
return;
}
/*
* SSH读取消息
* */
$read = function () use ($ssh) {
/*拼接*/
$raw = "";
/*读取空白次数*/
$blank = 0;
/*
* 循环读取
* */
while (true) {
$msg = $ssh->read('username@username:~$');
if (!empty($msg)) {
$raw .= $msg;
} else {
/*
* 空白10次,终止,返回
* */
if ($blank > 10) {
break;
} else {
$blank++;
}
}
}
return $raw;
};
/*读取间隔时间*/
$ssh->setTimeout(0.1);
$redis = getRedis(); //创建redis
/*
* 打开存放仓库的目录
* */
$root = "/home/repos/"; //存放仓库的目录
$ssh->write("cd " . $root . "\n");
echo $read(); //读取初始化的消息
/*
* Redis订阅等待消息
* */
$redis->subscribe(["RECV_GIT"], function ($redis, $chan, $msg) use ($ssh, $read, $root) {
echo "收到消息:" . $msg . "\n"; //收到消息
/*
* 判断消息内容是否包含分支信息
* */
if (strpos($msg, "branch") === false) return;
try {
$data = json_decode($msg, true); //处理结果
/*
* 判断仓库是否存在
* */
$path = $root . $data['path']; //本地仓库路径
/*
* 仓库目录是否存在
* */
if (!file_exists($path)) {
/*创建*/
mkdir($path);
/*打开仓库目录*/
$ssh->write("cd " . $path . "\n");
/*初始化仓库*/
$ssh->write("git init\n");
echo $read(); //读取后续的消息
/*添加远程仓库*/
$ssh->write("git remote add origin " . $data['clone'] . "\n");
echo $read(); //读取后续的消息
} else {
/*打开仓库目录*/
$ssh->write("cd " . $path . "\n");
}
/*拉取分支*/
$ssh->write("git pull origin " . $data['branch'] . ":" . $data['branch'] . " \n");
echo $read(); //读取后续的消息
} catch (\Throwable $e) {
echo $e->getMessage() . "\n";
}
});
打开上方Cli脚本所在目录,运行如下命令:
# 前台运行
php 文件名.php
# 后台台运行
nohup php 文件名.php &
每次脚本运行的日志,会自动写入到当前目录的nohup.out文件,作为日志方便观察同步结果 ;
运行之后,每次仓库有更新,脚本都会自动同步这一次的更新;本文只是简单的实现,您完全可以通过这个案例实现更复杂的功能。
erry Chrismas!
写程序时,我了省时间,省空间。我们对一个变量运行后,不再新建变量存储运算结果,直接赋值给该变量自身,这样很容易操作。特别是早期写PHP代码,在PHP代码中混入HTML语法,多行拼接的情况下,就会使用类似如下的方式:
上面代码取自某国产开源商城代码。为了拼接查询语句,$where在不同的case内,拼接不同的查询条件。
下面我们使用代码实例,演示一下操作结果:
代码如下:
/**
* ------------------------------------------------
* 下面是运算和赋值操作
* ------------------------------------------------
*/
$a = 1.542e-4;
$b = pow(2,5);
echo "a = " . $a . ", b = " . $b, "<br/>";
$b += 0.54;
echo "b = " . $b, "<br/>";
$b -= 7.5;
echo "b = " . $b, "<br/>";
$b *= mt_rand(1,10);
echo "b = " . $b, "<br/>";
$b /= 5;
echo "b = " . $b, "<br/>";
$b %= 3;
echo "b = " . $b, "<br/>";
// 自动转换为字符串
$b .= " - toString";
echo "b = " . $b, "<br/>";
在浏览器内访问 www.array.com/chapter1.5.php 得到如下结果:
注意,最后的 .= 操作符,是字符串连接。PHP将$b自动转换为字符串,并与右侧字符串拼接起来。这里面,有一个数据类型转换。
一切程序都要进行逻辑判断,无论是面向过程变成,拟或面向对象编程,条件判断散落在程序的角角落落,像空气一样,如影随形。
如果,想要把程序内的if...else...语句完全清除,几乎要使用更为高级的设计模式,以及系统重构。
初学者,本着思路走,先写一写if...else...的判断语句吧。
下面我们演示一下PHP中逻辑操作符。
代码如下:
/**
* ------------------------------------------------
* 下面是逻辑操作符
* ------------------------------------------------
*/
$a = 65;
$b = 47;
if ($a == $b) echo "a等于b", "<br/>";
if ($a != $b) echo "a不等于b", "<br/>";
if ($a === $b) echo "a全等于b", "<br/>";
if ($a !== $b) echo "a不全等于b", "<br/>";
if ($a <> $b) echo "a不等于b", "<br/>";
if ($a > $b) echo "a大于b", "<br/>";
if ($a < $b) echo "a小于b", "<br/>";
if ($a >= $b) echo "a大于等于b", "<br/>";
if ($a <= $b) echo "a小于等于b", "<br/>";
// 还有一个重量级的,太空船操作符
// 左边 > 右边,返回 1
// 左边 = 右边,返回 0
// 左边 < 右边,返回 -1
switch ($a <=> $b) {
case 1:
echo "a大于b", "<br/>";
break;
case 0:
echo "a等于b", "<br/>";
break;
case -1:
echo "a小于b", "<br/>";
break;
}
大于,小于,等于,不等于,基本很多编程语言相同,没什么说的。
上面演示的是两个数据类型相同的整数值的比较,如果不同类型的数据进行比较,PHP会按照约定规则进行数据类型转换。可参考官网章节。
特别说明的是“太空船操作符”,可以返回孰大孰小,或者等于。上面实例,使用了switch...case...选择分支结果,进行结果展现。读者可不必着急,下面一小节,就要将这个了。
同样地,在浏览器访问 www.array.com/chapter1.5.php ,可得以下结果:
读者可以根据上面的表达式,依次核对,那个逻辑条件执行了,那个没执行。
在PHP中发送邮件,通常都是封装一个php的smtp邮件类来发送邮件。但是PHP底层的socket编程相对于python来说效率是非常低的。CleverCode同时写过用python写的爬虫抓取网页,和用php写的爬虫抓取网页。发现虽然用了php的curl抓取网页,但是涉及到超时,多线程同时抓取等等。不得不说python在网络编程的效率要比PHP好的多。
PHP在发送邮件时候,自己写的smtp类,发送的效率和速度都比较低。特别是并发发送大量带有附件报表的邮件的时候。php的效率很低。建议可以使用php调用python的方式来发送邮件。
php的程序和python的文件必须是相同的编码。如都是gbk编号,或者同时utf-8编码,否则容易出现乱码。python发送邮件主要使用了email模块。这里python文件和php文件都是gbk编码,发送的邮件标题内容与正文内容也是gbk编码。
#!/usr/bin/python
# -*- coding:gbk -*-
"""
邮件发送类
"""
# mail.py
#
# Copyright (c) 2014 by http://blog.csdn.net/CleverCode
#
# modification history:
# --------------------
# 2014/8/15, by CleverCode, Create
import threading
import time
import random
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Utils, Encoders
import mimetypes
import sys
import smtplib
import socket
import getopt
import os
class SendMail:
def __init__(self,smtpServer,username,password):
"""
smtpServer:smtp服务器,
username:登录名,
password:登录密码
"""
self.smtpServer = smtpServer
self.username = username
self.password = password
def genMsgInfo(self,fromAddress,toAddress,subject,content,fileList,\
subtype = 'plain',charset = 'gb2312'):
"""
组合消息发送包
fromAddress:发件人,
toAddress:收件人,
subject:标题,
content:正文,
fileList:附件,
subtype:plain或者html
charset:编码
"""
msg = MIMEMultipart()
msg['From'] = fromAddress
msg['To'] = toAddress
msg['Date'] = Utils.formatdate(localtime=1)
msg['Message-ID'] = Utils.make_msgid()
#标题
if subject:
msg['Subject'] = subject
#内容
if content:
body = MIMEText(content,subtype,charset)
msg.attach(body)
#附件
if fileList:
listArr = fileList.split(',')
for item in listArr:
#文件是否存在
if os.path.isfile(item) == False:
continue
att = MIMEText(open(item).read(), 'base64', 'gb2312')
att["Content-Type"] = 'application/octet-stream'
#这里的filename邮件中显示什么名字
filename = os.path.basename(item)
att["Content-Disposition"] = 'attachment; filename=' + filename
msg.attach(att)
return msg.as_string()
def send(self,fromAddress,toAddress,subject = None,content = None,fileList = None,\
subtype = 'plain',charset = 'gb2312'):
"""
邮件发送函数
fromAddress:发件人,
toAddress:收件人,
subject:标题
content:正文
fileList:附件列表
subtype:plain或者html
charset:编码
"""
try:
server = smtplib.SMTP(self.smtpServer)
#登录
try:
server.login(self.username,self.password)
except smtplib.SMTPException,e:
return "ERROR:Authentication failed:",e
#发送邮件
server.sendmail(fromAddress,toAddress.split(',') \
,self.genMsgInfo(fromAddress,toAddress,subject,content,fileList,subtype,charset))
#退出
server.quit()
except (socket.gaierror,socket.error,socket.herror,smtplib.SMTPException),e:
return "ERROR:Your mail send failed!",e
return 'OK'
def usage():
"""
使用帮助
"""
print """Useage:%s [-h] -s <smtpServer> -u <username> -p <password> -f <fromAddress> -t <toAddress> [-S <subject> -c
<content> -F <fileList>]
Mandatory arguments to long options are mandatory for short options too.
-s, --smtpServer= smpt.xxx.com.
-u, --username= Login SMTP server username.
-p, --password= Login SMTP server password.
-f, --fromAddress= Sets the name of the "from" person (i.e., the envelope sender of the mail).
-t, --toAddress= Addressee's address. -t "test@test.com,test1@test.com".
-S, --subject= Mail subject.
-c, --content= Mail message.-c "content, ......."
-F, --fileList= Attachment file name.
-h, --help Help documen.
""" %sys.argv[0]
def start():
"""
"""
try:
options,args = getopt.getopt(sys.argv[1:],"hs:u:p:f:t:S:c:F:","--help --smtpServer= --username= --password= --fromAddress= --toAddress= --subject= --content= --fileList=",)
except getopt.GetoptError:
usage()
sys.exit(2)
return
smtpServer = None
username = None
password = None
fromAddress = None
toAddress = None
subject = None
content = None
fileList = None
#获取参数
for name,value in options:
if name in ("-h","--help"):
usage()
return
if name in ("-s","--smtpServer"):
smtpServer = value
if name in ("-u","--username"):
username = value
if name in ("-p","--password"):
password = value
if name in ("-f","--fromAddress"):
fromAddress = value
if name in ("-t","--toAddress"):
toAddress = value
if name in ("-S","--subject"):
subject = value
if name in ("-c","--content"):
content = value
if name in ("-F","--fileList"):
fileList = value
if smtpServer == None or username == None or password == None:
print 'smtpServer or username or password can not be empty!'
sys.exit(3)
mail = SendMail(smtpServer,username,password)
ret = mail.send(fromAddress,toAddress,subject,content,fileList)
if ret != 'OK':
print ret
sys.exit(4)
print 'OK'
return 'OK'
if __name__ == '__main__':
start()
输入以下命令,可以输出这个程序的使用帮助
# python mail.py --help
这个程序主要是php拼接命令字符串,调用python程序。注意:用程序发送邮件,需要到邮件服务商,开通stmp服务功能。如qq就需要开通smtp功能后,才能用程序发送邮件。开通如下图。
php调用程序如下:
<?php
/**
* SendMail.php
*
* 发送邮件类
*
* Copyright (c) 2015 by http://blog.csdn.net/CleverCode
*
* modification history:
* --------------------
* 2015/5/18, by CleverCode, Create
*
*/
class SendMail{
/**
* 发送邮件方法
*
* @param string $fromAddress 发件人,'clevercode@qq.com' 或者修改发件人名 'CleverCode<clevercode@qq.com>'
* @param string $toAddress 收件人,多个收件人逗号分隔,'test1@qq.com,test2@qq.com,test3@qq.com....', 或者 'test1<test1@qq.com>,test2<test2@qq.com>,....'
* @param string $subject 标题
* @param string $content 正文
* @param string $fileList 附件,附件必须是绝对路径,多个附件逗号分隔。'/data/test1.txt,/data/test2.tar.gz,...'
* @return string 成功返回'OK',失败返回错误信息
*/
public static function send($fromAddress, $toAddress, $subject = NULL, $content = NULL, $fileList = NULL){
if (strlen($fromAddress) < 1 || strlen($toAddress) < 1) {
return '$fromAddress or $toAddress can not be empty!';
}
// smtp服务器
$smtpServer = 'smtp.qq.com';
// 登录用户
$username = 'clevercode@qq.com';
// 登录密码
$password = '123456';
// 拼接命令字符串,实际是调用了/home/CleverCode/mail.py
$cmd = "LANG=C && /usr/bin/python /home/CleverCode/mail.py";
$cmd .= " -s '$smtpServer'";
$cmd .= " -u '$username'";
$cmd .= " -p '$password'";
$cmd .= " -f '$fromAddress'";
$cmd .= " -t '$toAddress'";
if (isset($subject) && $subject != NULL) {
$cmd .= " -S '$subject'";
}
if (isset($content) && $content != NULL) {
$cmd .= " -c '$content'";
}
if (isset($fileList) && $fileList != NULL) {
$cmd .= " -F '$fileList'";
}
// 执行命令
exec($cmd, $out, $status);
if ($status == 0) {
return 'OK';
} else {
return "Error,Send Mail,$fromAddress,$toAddress,$subject,$content,$fileList ";
}
return 'OK';
}
}
压缩excel成附件,发送邮件。
<?php
/**
* test.php
*
* 压缩excel成附件,发送邮件
*
* Copyright (c) 2015 http://blog.csdn.net/CleverCode
*
* modification history:
* --------------------
* 2015/5/14, by CleverCode, Create
*
*/
include_once ('SendMail.php');
/*
* 客户端类
* 让客户端和业务逻辑尽可能的分离,降低页面逻辑和业务逻辑算法的耦合,
* 使业务逻辑的算法更具有可移植性
*/
class Client{
public function main(){
// 发送者
$fromAddress = 'CleverCode<clevercode@qq.com>';
// 接收者
$toAddress = 'all@qq.com';
// 标题
$subject = '这里是标题!';
// 正文
$content = "您好:\r\n";
$content .= " 这里是正文\r\n ";
// excel路径
$filePath = dirname(__FILE__) . '/excel';
$sdate = date('Y-m-d');
$PreName = 'CleverCode_' . $sdate;
// 文件名
$fileName = $filePath . '/' . $PreName . '.xls';
// 压缩excel文件
$cmd = "cd $filePath && zip $PreName.zip $PreName.xls";
exec($cmd, $out, $status);
$fileList = $filePath . '/' . $PreName . '.zip';
// 发送邮件(附件为压缩后的文件)
$ret = SendMail::send($fromAddress, $toAddress, $subject, $content, $fileList);
if ($ret != 'OK') {
return $ret;
}
return 'OK';
}
}
/**
* 程序入口
*/
function start(){
$client = new Client();
$client->main();
}
start();
?>
http://download.csdn.net/detail/clevercode/8711809
版权声明:
1)原创作品,出自"CleverCode的博客",转载时请务必注明以下原创地址,否则追究版权法律责任。
2)原创地址:http://blog.csdn.net/clevercode/article/details/45815453(转载务必注明该地址)。
3)欢迎大家关注我博客更多的精彩内容:http://blog.csdn.net/CleverCode。
*请认真填写需求信息,我们会在24小时内与您取得联系。