DiscuzX/upload/source/class/discuz/discuz_patch.php

364 lines
9.0 KiB
PHP
Raw Normal View History

2016-12-15 08:20:54 -05:00
<?php
/**
* [Discuz!] (C)2001-2099 Comsenz Inc.
* This is NOT a freeware, use is subject to license terms
*
* $Id: discuz_patch.php 33628 2013-07-22 03:48:48Z jeffjzhang $
*/
if(!defined('IN_DISCUZ')) {
exit('Access Denied');
}
class discuz_patch {
public function save_patch_setting($settingnew) {
if($settingnew['patch']['autoopened'] && !$this->test_writable(DISCUZ_ROOT)) {
return false;
}
C::t('common_setting')->update_batch($settingnew);
include_once libfile('function/cache');
updatecache('setting');
return true;
}
public function fetch_patch_notice() {
global $_G;
$serials = $fixed_serials = $unfixed_serials = array();
$showpatchnotice = 1;
$serials = C::t('common_patch')->fetch_all();
if($serials) {
foreach($serials as $serial) {
if($serial['status'] <= 0) {
$showpatchnotice = 2;
$unfixed_serials[] = $serial;
} else {
$fixed_serials[] = $serial;
}
}
}
if($showpatchnotice == 2) {
$serials = $unfixed_serials;
} else {
C::t('common_setting')->delete('showpatchnotice');
include_once libfile('function/cache');
updatecache('setting');
}
return array('fixed' => (!empty($serials) && $showpatchnotice == 1) ? 1 : 0, 'data' => $serials);
}
public function check_patch($ignore = 0) {
global $_G;
if(!$ignore && $_G['cookie']['checkpatch']) {
return false;
}
require_once DISCUZ_ROOT.'source/discuz_version.php';
require_once libfile('class/xml');
$versionpath = '';
foreach(explode(' ', substr(DISCUZ_VERSION, 1)) as $unit) {
$versionpath = $unit;
break;
}
$patchdir = 'http://upgrade.discuz.com/DiscuzX/'.$versionpath.'/';
$checkurl = $patchdir.'md5sums';
$patchlist = dfsockopen($checkurl);
if(defined('DISCUZ_FIXBUG')) {
C::t('common_patch')->update_status_by_serial(1, DISCUZ_FIXBUG, '<=');
}
if($patchlist) {
$serial_md5s = explode("\r\n", $patchlist);
$bound = intval(substr($serial_md5s[count($serial_md5s)-2], 0, 8));
$maxpatch = intval(C::t('common_patch')->fetch_max_serial());
if(defined('DISCUZ_FIXBUG')) {
$maxpatch = $maxpatch < DISCUZ_FIXBUG ? DISCUZ_FIXBUG : $maxpatch;
}
if($bound > $maxpatch) {
$insertarrlist = array();
foreach($serial_md5s as $serial_md5) {
$downloadpatch = $patch = '';
list($serial, $md5, $release) = explode(' ', $serial_md5);
if($serial > $maxpatch && (!$release || in_array(DISCUZ_RELEASE, explode(',', $release)))) {
$downloadpatch = $patchdir.$serial.'.xml';
$patch = dfsockopen($downloadpatch);
if(md5($patch) != $md5) {
continue;
}
$patch = xml2array($patch);
if(is_array($patch) && !empty($patch)) {
$insertarr = array(
'serial' => intval($patch['serial']),
'rule' => serialize($patch['rule']),
'note' => $patch['note'],
'status' => 0,
'dateline' => $patch['dateline'],
);
C::t('common_patch')->insert($insertarr);
$insertarrlist[$insertarr['serial']] = $insertarr;
}
}
}
if($insertarrlist && $_G['setting']['patch']['autoopened']) {
foreach($insertarrlist as $key => $patch) {
$this->fix_patch($patch);
}
}
if($insertarrlist) {
C::t('common_setting')->update('showpatchnotice', 1);
include_once libfile('function/cache');
updatecache('setting');
}
}
}
dsetcookie('checkpatch', 1, 60);
return true;
}
public function fix_patch($patch, $type = 'file') {
global $_G;
$serial = $patch['serial'];
if(!$serial) {
return -1;
}
$returnflag = 1;
$trymax = 1000;
$rules = dunserialize($patch['rule']);
$tmpfiles = $bakfiles = array();
if($type == 'ftp') {
$siteftp = $_GET['siteftp'];
}
foreach($rules as $rule) {
$filename = DISCUZ_ROOT.$rule['filename'];
$search = base64_decode($rule['search']);
$replace = base64_decode($rule['replace']);
$count = $rule['count'];
$nums = $rule['nums'];
if(!$siteftp && !is_writable($filename)) {
$returnflag = -2;
break;
}
$str = file_get_contents($filename);
$findcount = substr_count($str, $search);
if($findcount != $count) {
$returnflag = 2;
break;
}
$bakfile = basename($rule['filename']);
$bakfile = '_'.$serial.'_'.substr($bakfile, 0, strrpos($bakfile, '.')).'_'.substr(md5($_G['config']['security']['authkey']), -6).'.bak.'.substr($bakfile, strrpos($bakfile, '.') +1);
$bakfile = $siteftp ? dirname($rule['filename']).'/'.$bakfile : dirname($filename).'/'.$bakfile;
$tmpfile = tempnam(DISCUZ_ROOT.'./data', 'patch');
$strarr = explode($search, $str);
$replacestr = '';
foreach($strarr as $key => $value) {
if($key == $findcount) {
$replacestr .= $value;
} else {
if(in_array(($key + 1), $nums)) {
$replacestr .= $value.$replace;
} else {
$replacestr .= $value.$search;
}
}
}
if(!file_put_contents($tmpfile, $replacestr)) {
$returnflag = -3;
break;
}
if($siteftp) {
if(!file_exists(DISCUZ_ROOT.$bakfile) && !$this->copy_file($filename, $bakfile, 'ftp')) {
$returnflag = -4;
break;
}
$i = 0;
while(!$this->copy_file($tmpfile, $rule['filename'], 'ftp')) {
if($i >= $trymax) {
$returnflag = -4;
break;
}
$i++;
}
} else {
if(!file_exists($bakfile) && !$this->copy_file($filename, $bakfile, 'file')) {
$returnflag = -5;
break;
}
$i = 0;
while(!$this->copy_file($tmpfile, $filename, 'file')) {
if($i >= $trymax) {
$returnflag = -5;
break;
}
$i++;
}
}
$tmpfiles[] = $tmpfile;
$bakfiles[] = $bakfile;
}
if($returnflag < 0) {
if(!empty($bakfiles)) {
foreach($bakfiles as $backfile) {
if($siteftp) {
$i = 0;
while(!$this->copy_file($backfile, substr($backfile, -12), 'ftp')) {
if($i >= $trymax) {
$returnflag = -6;
break;
}
$i++;
}
} else {
$i = 0;
while(!$this->copy_file($backfile, substr($backfile, -12), 'file')) {
if($i >= $trymax) {
$returnflag = -6;
break;
}
$i++;
}
}
}
}
}
if(!empty($tmpfiles)) {
foreach($tmpfiles as $tmpfile) {
@unlink($tmpfile);
}
}
C::t('common_patch')->update($serial, array('status' => $returnflag));
return $returnflag;
}
public function test_writable($sdir) {
$dir = opendir($sdir);
while($entry = readdir($dir)) {
$file = $sdir.$entry;
if($entry != '.' && $entry != '..') {
if(is_dir($file) && !strrpos($file.'/', '.svn')) {
if(!self::test_writable($file.'/')) {
return false;
}
}
}
}
if($fp = @fopen("$sdir/test.txt", 'w')) {
@fclose($fp);
@unlink("$sdir/test.txt");
$writeable = true;
} else {
$writeable = false;
}
return $writeable;
}
public function test_patch_writable($patch) {
$rules = dunserialize($patch['rule']);
if($rules) {
foreach($rules as $rule) {
if(!is_writable(DISCUZ_ROOT.$rule['filename'])) {
return false;
}
}
return true;
}
return false;
}
public function copy_file($srcfile, $desfile, $type) {
global $_G;
if(!is_file($srcfile)) {
return false;
}
if($type == 'file') {
$this->mkdirs(dirname($desfile));
copy($srcfile, $desfile);
} elseif($type == 'ftp') {
$siteftp = $_GET['siteftp'];
$siteftp['on'] = 1;
$siteftp['password'] = authcode($siteftp['password'], 'ENCODE', md5($_G['config']['security']['authkey']));
$ftp = & discuz_ftp::instance($siteftp);
$ftp->connect();
$ftp->upload($srcfile, $desfile);
if($ftp->error()) {
return false;
}
}
return true;
}
public function mkdirs($dir) {
if(!is_dir($dir)) {
if(!self::mkdirs(dirname($dir))) {
return false;
}
if(!mkdir($dir)) {
return false;
}
}
return true;
}
public function test_patch($patch) {
$serial = $patch['serial'];
$rules = dunserialize($patch['rule']);
foreach($rules as $rule) {
$filename = DISCUZ_ROOT.$rule['filename'];
$search = base64_decode($rule['search']);
$replace = base64_decode($rule['replace']);
$count = $rule['count'];
$nums = $rule['nums'];
$str = file_get_contents($filename);
$findcount = substr_count($str, $search);
if($findcount != $count) {
return true;
}
$replacefindcount = substr_count($str, $replace);
if($replacefindcount == $count) {
return true;
}
}
return false;
}
public function recheck_patch() {
$updatestatus = array();
$patchlist = C::t('common_patch')->fetch_patch_by_status(array(1,2));
foreach($patchlist as $patch) {
if(!$this->test_patch($patch)) {
$updatestatus[] = $patch['serial'];
}
}
if($updatestatus) {
C::t('common_patch')->update_status_by_serial(0, $updatestatus);
}
return true;
}
}
?>