V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
liujiantao
V2EX  ›  PHP

撸了个差量更新,但无法正常运行,求指导

  •  
  •   liujiantao · 2015-03-22 09:37:07 +08:00 · 3146 次点击
    这是一个创建于 3525 天前的主题,其中的信息可能已经有所发展或是发生改变。

    自己做了个差量更新下来,但无法正常使用

    问题描述

    就是为了给KK的云签服务的,服务端是直接检测文件MD5值,然后程序端这边检测,下载。

    现在问题来了,可以正常检测到文件差异,但更新不下来或者说是(无法下载文件)可是是利用其他思路的可以正常下载文件,说明服务器本身没有问题,请各位大神帮我看下程序上有没有什么问题。

    程序代码

    服务端

    <?php
    define('UPDATA_SOURCE', './Tieba'); //这个目录就是用来检查差异文件的
    chdir(UPDATA_SOURCE);
    if($_GET['action'] == 'filelist') {
        $dirs = array('./');
        $rt = array();
        do {
            $dir = array_pop($dirs);
            $tmp = scandir($dir);
    
            foreach($tmp as $f) {
                if($f == '.' || $f == '..')
                    continue;
    
                $path = $dir . $f;
    
                if(is_dir($path)) {
                    array_push($dirs, $path . '/');
                } elseif (is_file($path)) {
                    $rt [] = $path;
                }
            }
        } while($dirs);
    
        foreach($rt as $file){
            $str[$file] = md5_file($file);
        }
    
        echo json_encode($str);
        exit();
    } elseif($_GET['action'] == 'getfile') {
        if (!file_exists($_GET['path'])){
            header("Content-type: text/html; charset=utf-8");
            echo "File not found!";
            exit; 
        } else {
            $file = fopen($_GET['path'], "r"); 
            header("Content-type: application/octet-stream");
            header("Accept-Ranges: bytes");
            header("Accept-Length: " . filesize($_GET['path']));
            header("Content-Disposition: attachment; filename=" . array_pop(explode('/', $_GET['path'])));
            echo fread($file, filesize($_GET['path']));
            fclose($file);
            exit;
        }
    }
    ?>
    

    程序端

    <?php
    if(!defined('IN_KKFRAME')) exit('Access Denied');
    class Updater{
        const UPDATE_URL = 'http://update.liujiantao.me/';
        public static function init(){
            global $_config;
            if($_config['version']){
                $current_version = $_config['version'];
            } else {
                $current_version = getSetting('version');
            }
            if ($current_version == VERSION) return;
            $version = $current_version;
            while($version){
                $filepath = SYSTEM_ROOT."./function/updater/{$version}.php";
                if(file_exists($filepath)){
                    include $filepath;
                    exit();
                } else{
                    $version = substr($version, 0, strrpos($version, '.'));
                }
            }
            include SYSTEM_ROOT.'./function/updater/fallback.php';
            exit();
        }
        public static function check(){
            $data = kk_fetch_url(self::UPDATE_URL."updata.php?action=filelist");
            saveSetting('new_version', 0);
            if (!$data) return -1;
            $file_list = json_decode($data);
            if (!$file_list) return -2;
            $err_file = $list = array();
            foreach($file_list as $path => $hash) {
                $file_hash = md5_file(ROOT."./{$path}");
                if ($file_hash != $hash){
                    $err_file[] = array($path, $hash);
                    $list[] = $path;
                }
            }
            if(!$list) return 0;
            saveSetting('new_version', 1);
            sort($list);
            sort($err_file);
            CACHE::save('kk_updater', $err_file);
            CACHE::save('need_download', $err_file);
            DB::query('DELETE FROM download');
            return $list;
        }
        public static function loop(){
            if(defined('IN_XAE')) return array('status' => -3);
            $file_list = CACHE::get('need_download');
            list($path, $hash) = array_pop($file_list);
            if(!$path) return array('status' => 1);
            $ret = self::_download_file($path, $hash);
            if ($ret<0) return array('status' => $ret, 'file' => $path);
            CACHE::save('need_download', $file_list);
            $max = sizeof(CACHE::get('kk_updater'));
            $current = $max - sizeof($file_list);
            return array('status' => 0, 'precent' => round($current / $max * 100), 'file' => $path);
        }
        public static function write_file(){
            $err_file = $files = array();
            $query = DB::query('SELECT * FROM download ORDER BY path ASC');
            while($file = DB::fetch($query)){
                list($part, $path) = explode('|', $file['path'], 2);
                if(!$files[ $path ]){
                    $file['content'] = pack('H*', $file['content']);
                    $files[ $path ] = $file;
                } else {
                    $files[ $path ]['content'] .= pack('H*', $file['content']);
                }
            }
            if(!$files) return array('status' => -255);
            foreach($files as $path => $file) {
                if(!self::_is_writable(ROOT.$path)) $err_file[] = $path;
            }
            if($err_file) array('status' => -1, 'files' => $err_file);
            foreach($files as $path => $file) {
                self::_write(ROOT.$path, $file['content']);
                if(md5_file(ROOT.$path) != md5($file['content'])) return array('status' => -2, 'file' => $path);
            }
            DB::query('DELETE FROM download');
            saveSetting('new_version', 0);
            return array('status' => 0);
        }
        private static function _write($path, $content){
            $fp = @fopen($path, 'wb');
            if(!$fp) return false;
            fwrite($fp, $content);
            fclose($fp);
            return true;
        }
        private static function _is_writable($path){
            if(!file_exists($path)){
                if(!file_exists(dirname($path))) @mkdir(dirname($path), 0777, true);
                @touch($path);
                @chmod($path, 0777);
            }else{
                if(!is_writable($path)) @chmod($path, 0777);
            }
            return is_writable($path);
        }
        private static function _download_file($path, $hash, $try = 1) {
            $content = kk_fetch_url(self::UPDATE_URL."updata.php?action=getfile&path={$path}");
            if (!$content) {
                if ($try == 3) {
                    return -1;
                } else {
                    return self::_download_file($path, $hash, $try + 1);
                }
            }
            if (md5($content) != $hash) {
                if ($try == 3) {
                    return -2;
                } else {
                    return self::_download_file($path, $hash, $try + 1);
                }
            }
            $length = $part = 0;
            while($length < strlen($content)){
                $part++;
                $part_length = strlen($content) - $length > 8192 ? 8192 : strlen($content) - $length;
                $_countent = substr($content, $length, $part_length);
                $length += $part_length;
                $_part = str_pad($part, 4, "0", STR_PAD_LEFT);
                DB::insert('download', array('path' => "{$_part}|".$path, 'content' => bin2hex($_countent)));
            }
            return 0;
        }
        private static function _getPluginList(){
            $pluginList = array();
            $list_dir = dir(ROOT.'./plugins/');
            while($dirName = $list_dir->read()){
                if($dirName == '.' || $dirName == '..' || !is_dir(ROOT."./plugins/{$dirName}")) continue;
                $pluginList[] = $dirName;
            }
            return $pluginList;
        }
    }
    ?>
    

    演示

    检查更新:

    检查更新

    无法更新:

    点击后显示更新成功,但文件无改动
    无法更新

    完整代码

    程序端完整代码在这里: https://github.com/liujiantaoliu/Tieba_Sign

    服务端代码就是上面的

    还请各位大神帮忙看下,感激不尽!
    联系方式:QQ:3720-753-00

    11 条回复    2015-03-24 13:14:41 +08:00
    Actrace
        1
    Actrace  
       2015-03-22 10:00:08 +08:00
    你确定目录可读写。。。?
    yangff
        2
    yangff  
       2015-03-22 10:07:41 +08:00 via Android
    你是部署在VPS/独服还是xx云(比如bae、sae)上的?
    liujiantao
        3
    liujiantao  
    OP
       2015-03-22 10:43:04 +08:00
    @yangff VPS上,都是在VPS
    liujiantao
        4
    liujiantao  
    OP
       2015-03-22 10:43:33 +08:00
    @Actrace 可以的,利用其他思路的可以正常更新:**下载zip,解压**
    Actrace
        5
    Actrace  
       2015-03-22 10:48:05 +08:00
    如果是诊断为无法下载,那么你得根据debug日志来做调整了。
    另外我是不建议在文件输出环节做太多操作,直接一个echo file()来输出内容就可以了。
    接受端则是file_get_contents.
    liujiantao
        6
    liujiantao  
    OP
       2015-03-22 10:51:38 +08:00
    @Actrace 我是利用服务端updata.php比对文件MD5值,程序端在进行比对,找出不同的进行下载更新,可就是不知道为什么能正常检测更新就是没法回传回来,我直接通过URL是可以正常下载文件的,不知道是不是程序端代码有什么问题
    haiyang416
        7
    haiyang416  
       2015-03-22 11:06:15 +08:00
    代码太乱了,就不看了。
    直接在 _download_file 方法里下断言,就知道问题出在哪里了。
    kookxiang
        8
    kookxiang  
       2015-03-22 15:00:28 +08:00 via Android
    本来就有差量更新,何必重复造轮子

    记得r是读不了php的,就算能读,你程序也有严重漏洞,文件名没过滤直接读到服务器上的任意文件
    liujiantao
        9
    liujiantao  
    OP
       2015-03-22 16:14:34 +08:00
    @kookxiang 知道有差量更新,可我们没有服务器端的文件,怎么做呢,漏洞找个时间修复
    branchzero
        10
    branchzero  
       2015-03-23 05:38:44 +08:00
    咦,KK已经出现了233333,代码有点乱。。。还是自己设置断点来追踪吧
    liujiantao
        11
    liujiantao  
    OP
       2015-03-24 13:14:41 +08:00 via Android
    @branchzero 啊哈
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3577 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 05:01 · PVG 13:01 · LAX 21:01 · JFK 00:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.