PHP 之简单在线更新

一、效果图

 

 

 二、示例代码

1、客户端

common.php

<?php
/**
 * Created by PhpStorm.
 * User: Mr.Yang
 * Date: 2022/5/11
 * Time: 15:24
 * QQ: 2575404985
 */

define('ROOT_PATH', dirname(__FILE__));

// 执行URL请求,并返回数据
function get_url($url, $fields = array(), $UserAgent = null, $vfSSL = false)
{
    $SSL = substr($url, 0, 8) == "https://" ? true : false;

    $ch = curl_init();
    if ($UserAgent) { // 在HTTP请求中包含一个"User-Agent: "头的字符串。
        curl_setopt($ch, CURLOPT_USERAGENT, $UserAgent);
    } else {
        curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER["HTTP_USER_AGENT"]);
    }
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60); // 在发起连接前等待的时间,如果设置为0,则无限等待
    curl_setopt($ch, CURLOPT_TIMEOUT, 90); // 设置cURL允许执行的最长秒数
    curl_setopt($ch, CURLOPT_URL, $url); // 设置请求地址
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 设置cURL 参数,要求结果保存到字符串中还是输出到屏幕上。

    // SSL验证
    if ($SSL) {
        if ($vfSSL) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
            curl_setopt($ch, CURLOPT_CAINFO, CORE_PATH . '/cacert.pem');
        } else {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // 不检查证书中是否设置域名
        }
    }

    // 数据字段
    if ($fields) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
    }

    $output = curl_exec($ch);
    if (curl_errno($ch)) {
        error('请求远程地址错误:' . curl_error($ch));
    }
    curl_close($ch);
    return $output;
}

// 递归替换
function preg_replace_r($search, $replace, $subject)
{
    while (preg_match($search, $subject)) {
        $subject = preg_replace($search, $replace, $subject);
    }
    return $subject;
}

// 检测目录是否存在
function check_dir($path, $create = false)
{
    if (is_dir($path)) {
        return true;
    } elseif ($create) {
        return create_dir($path);
    }
}

// 创建目录
function create_dir($path)
{
    if (! file_exists($path)) {
        if (mkdir($path, 0777, true)) {
            return true;
        }
    }
    return false;
}

// 检查文件是否存在
function check_file($path, $create = false, $content = null)
{
    if (file_exists($path)) {
        return true;
    } elseif ($create) {
        return create_file($path, $content);
    }
}

// 创建文件
function create_file($path, $content = null, $over = false)
{
    if (file_exists($path) && ! $over) {
        return false;
    } elseif (file_exists($path)) {
        @unlink($path);
    }
    check_dir(dirname($path), true);
    $handle = fopen($path, 'w') or die('创建文件失败,请检查目录权限!');
    fwrite($handle, $content);
    return fclose($handle);
}
View Code

index.php

<?php

extract($_REQUEST);
$action = $action ? $action : 'index';
include_once 'common.php';
$url = "服务端地址";
$files = json_decode(get_url($url . "/upgrade.php"), true);
//var_dump($files);
foreach ($files as $key => $value) {
    // 过滤掉相对路径
    $value['path'] = preg_replace_r('{\.\.(\/|\\\\)}', '', $value['path']);
    $file = ROOT_PATH . $value['path'];
    if (@md5(@file_get_contents($file)) != $value['md5']) {
        // 筛选数据库更新脚本
        if (preg_match('/([\w]+)-([\w\.]+)-update\.sql/i', $file, $matches)) {
            if ($matches[1] != 'mysql' || $matches[2] != '1.0.0') {
                continue;
            }
        }
        if (file_exists($file)) {
            $files[$key]['type'] = '<span style="color:Red">覆盖</span>';
            $files[$key]['ltime'] = date('Y-m-d H:i:s', filemtime($file));
        } else {
            $files[$key]['type'] = '新增';
            $files[$key]['ltime'] = '无';
        }
        $files[$key]['ctime'] = date('Y-m-d H:i:s', $files[$key]['ctime']);
        $upfile[] = $files[$key];
    }
}
if (!$upfile) {
    die("您的系统无任何文件需要更新!");
}

if ($action=='download') {
    foreach ($upfile as $k => $v){
        //获取内容
        $res = json_decode(file_get_contents($url."/upgrade.php?action=getFile&path=".$v['path']), true);
        if ($res['code'] == 0){
            $file = ROOT_PATH . $v['path'];
            //判断是否有目录,没有则创建
            check_dir(dirname($file), true);
            //备份对应文件
            $back = ROOT_PATH."/upgrade/".date("YmdHis").$v['path'];
            check_dir(dirname($back), true);
            copy($file, $back);
            $data = base64_decode($res['data']);
            
            //判断是否为数据库文件
            if (!file_put_contents($file, $data)){
                echo "文件 " . basename($v['path']) . " 更新失败!<br>";
            }else{
                if (stripos($v['path'], '/db/') === 0 && preg_match('/\.sql$/i', $v['path']) > 0) {
                    $sqls = explode(';', $data);
                    var_dump($sqls);
                }
                echo "文件 " . basename($v['path']) . " 更新成功!<br>";
            }
        }else{
            echo "文件 " . basename($v['path']) . " 更新失败!<br>";
        }
    }
}

?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>在线更新</title>
</head>
<style>
    th {
        background-color: #f2f2f2;
    }
    td, th {
        padding: 9px 15px;
        min-height: 20px;
        line-height: 20px;
        font-size: 14px;
    }
</style>
<body>
<?php if ($action == 'index'){?>
    <table style="width: 100%;text-align: center;background-color: #fff;color: #666;">
        <thead>
        <tr>
            <th>更新文件</th>
            <th>更新方式</th>
            <th>本地时间</th>
            <th>更新时间</th>
        </tr>
        </thead>
        <tbody>
        <?php foreach ($upfile as $k => $v){?>
            <tr>
                <td><?php echo $v['path']?></td>
                <td><?php echo $v['type']?></td>
                <td><?php echo $v['ltime']?></td>
                <td><?php echo $v['ctime']?></td>
            </tr>
        <?php }?>
        </tbody>
    </table>
<?php }?>
<div style="text-align: center;margin-top: 20px;">
    <a href="index.php">重新检查</a> &nbsp;&nbsp;&nbsp;&nbsp;<?php if($action != 'download'){?><a href="index.php?action=download">下载更新</a><?php }?>
</div>
</body>
</html>

2、服务端

upgrade.php

<?php
/**
 * Created by PhpStorm.
 * User: Mr.Yang
 * Date: 2022/5/11
 * Time: 15:04
 * QQ: 2575404985
 */

extract($_REQUEST);
$action = $action ? $action : '';

switch ($action){
    case 'getFile':
        if (file_exists("./release/".$path)){
            $content = base64_encode(file_get_contents("./release/".$path));
            die(json_encode(array('code' => 0, 'data' => $content)));
        }else{
            die(json_encode(array('code' => -1, 'data' => '')));
        }
        break;
    default:
        $file = getSourceFile();
        $file_array = array();
        foreach ($file as $k => $v){
            $content = file_get_contents($v);
            if ($v == './upgrade.php'){
                continue;
            }
            $file_array[] = array(
                'path' => str_replace('./release', '', $v),
                'md5' => md5($content),
                'ctime' => filemtime($v)
            );
        }
        die(json_encode($file_array, JSON_UNESCAPED_UNICODE));
}


function getSourceFile($path = './release')
{
    static $arr = array();
    if (is_dir($path)) {
        $array = glob($path . '/*');
        foreach ($array as $k => $v) {
            if (is_dir($v)) {
                getSourceFile($v);
            }else{
                $arr[] = $v;
            }
        }
    } else {
        $arr = $path;
    }
    return $arr;
}

 

posted @ 2022-12-16 13:13  样子2018  阅读(139)  评论(0编辑  收藏  举报