PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/module/backup/model.php

https://github.com/easysoft/zentaopms
PHP | 433 lines | 327 code | 34 blank | 72 comment | 20 complexity | 116b9d782bbf34b0f92e3e160a3c604c MD5 | raw file
  1. <?php
  2. /**
  3. * The model file of backup module of ZenTaoCMS.
  4. *
  5. * @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Yidong Wang <yidong@cnezsoft.com>
  8. * @package backup
  9. * @version $Id$
  10. * @link http://www.zentao.net
  11. */
  12. class backupModel extends model
  13. {
  14. /**
  15. * Backup SQL.
  16. *
  17. * @param string $backupFile
  18. * @access public
  19. * @return object
  20. */
  21. public function backSQL($backupFile)
  22. {
  23. $zdb = $this->app->loadClass('zdb');
  24. return $zdb->dump($backupFile);
  25. }
  26. /**
  27. * Backup file.
  28. *
  29. * @param string $backupFile
  30. * @access public
  31. * @return object
  32. */
  33. public function backFile($backupFile)
  34. {
  35. $zfile = $this->app->loadClass('zfile');
  36. $return = new stdclass();
  37. $return->result = true;
  38. $return->error = '';
  39. if(!is_dir($backupFile)) mkdir($backupFile, 0777, true);
  40. $tmpLogFile = $this->getTmpLogFile($backupFile);
  41. $dataDir = $this->app->getAppRoot() . 'www/data/';
  42. $count = $zfile->getCount($dataDir);
  43. file_put_contents($tmpLogFile, json_encode(array('allCount' => $count)));
  44. $result = $zfile->copyDir($dataDir, $backupFile, $logLevel = false, $tmpLogFile);
  45. $this->processSummary($backupFile, $result['count'], $result['size'], $result['errorFiles'], $count);
  46. unlink($tmpLogFile);
  47. return $return;
  48. }
  49. /**
  50. * Backup code.
  51. *
  52. * @param string $backupFile
  53. * @access public
  54. * @return object
  55. */
  56. public function backCode($backupFile)
  57. {
  58. $zfile = $this->app->loadClass('zfile');
  59. $return = new stdclass();
  60. $return->result = true;
  61. $return->error = '';
  62. $tmpLogFile = $this->getTmpLogFile($backupFile);
  63. $appRoot = $this->app->getAppRoot();
  64. $fileList = glob($appRoot . '*');
  65. $wwwFileList = glob($appRoot . 'www/*');
  66. $tmpFile = array_search($appRoot . 'tmp', $fileList);
  67. $wwwFile = array_search($appRoot . 'www', $fileList);
  68. $dataFile = array_search($appRoot . 'www/data', $wwwFileList);
  69. unset($fileList[$tmpFile]);
  70. unset($fileList[$wwwFile]);
  71. unset($wwwFileList[$dataFile]);
  72. $fileList = array_merge($fileList, $wwwFileList);
  73. if(!is_dir($backupFile)) mkdir($backupFile, 0777, true);
  74. $allCount = 0;
  75. foreach($fileList as $codeFile) $allCount += $zfile->getCount($codeFile);
  76. file_put_contents($tmpLogFile, json_encode(array('allCount' => $allCount)));
  77. $copiedCount = 0;
  78. $copiedSize = 0;
  79. $errorFiles = array();
  80. foreach($fileList as $codeFile)
  81. {
  82. $file = trim(str_replace($appRoot, '', $codeFile), DS);
  83. if(is_dir($codeFile))
  84. {
  85. if(!is_dir($backupFile . DS . $file)) mkdir($backupFile . DS . $file, 0777, true);
  86. $result = $zfile->copyDir($codeFile, $backupFile . DS . $file, $logLevel = false, $tmpLogFile);
  87. $copiedCount += $result['count'];
  88. $copiedSize += $result['size'];
  89. $errorFiles += $result['errorFiles'];
  90. }
  91. else
  92. {
  93. $dirName = dirname($file);
  94. if(!is_dir($backupFile . DS . $dirName)) mkdir($backupFile . DS . $dirName, 0777, true);
  95. if($zfile->copyFile($codeFile, $backupFile . DS . $file))
  96. {
  97. $copiedCount += 1;
  98. $copiedSize += filesize($codeFile);
  99. }
  100. else
  101. {
  102. $errorFiles[] = $codeFile;
  103. }
  104. }
  105. }
  106. $this->processSummary($backupFile, $copiedCount, $copiedSize, $errorFiles, $allCount);
  107. unlink($tmpLogFile);
  108. return $return;
  109. }
  110. /**
  111. * Restore SQL.
  112. *
  113. * @param string $backupFile
  114. * @access public
  115. * @return object
  116. */
  117. public function restoreSQL($backupFile)
  118. {
  119. $zdb = $this->app->loadClass('zdb');
  120. $nosafe = strpos($this->config->backup->setting, 'nosafe') !== false;
  121. $backupDir = dirname($backupFile);
  122. $fileName = date('YmdHis') . mt_rand(0, 9);
  123. $backFileName = "{$backupDir}/{$fileName}.sql";
  124. if(!$nosafe) $backFileName .= '.php';
  125. $result = $this->backSQL($backFileName);
  126. if($result->result and !$nosafe) $this->addFileHeader($backFileName);
  127. $allTables = $zdb->getAllTables();
  128. foreach($allTables as $tableName => $tableType)
  129. {
  130. try
  131. {
  132. $this->dbh->query("DROP $tableType IF EXISTS `$tableName`");
  133. }
  134. catch(PDOException $e){}
  135. }
  136. return $zdb->import($backupFile);
  137. }
  138. /**
  139. * Restore File.
  140. *
  141. * @param string $backupFile
  142. * @access public
  143. * @return object
  144. */
  145. public function restoreFile($backupFile)
  146. {
  147. $return = new stdclass();
  148. $return->result = true;
  149. $return->error = '';
  150. if(is_file($backupFile))
  151. {
  152. $oldDir = getcwd();
  153. chdir($this->app->getTmpRoot());
  154. $this->app->loadClass('pclzip', true);
  155. $zip = new pclzip($backupFile);
  156. if($zip->extract(PCLZIP_OPT_PATH, $this->app->getAppRoot() . 'www/data/', PCLZIP_OPT_TEMP_FILE_ON) == 0)
  157. {
  158. $return->result = false;
  159. $return->error = $zip->errorInfo();
  160. }
  161. chdir($oldDir);
  162. }
  163. elseif(is_dir($backupFile))
  164. {
  165. $zfile = $this->app->loadClass('zfile');
  166. $zfile->copyDir($backupFile, $this->app->getAppRoot() . 'www/data/', $showDetails = false);
  167. }
  168. return $return;
  169. }
  170. /**
  171. * Add file header.
  172. *
  173. * @param string $fileName
  174. * @access public
  175. * @return bool
  176. */
  177. public function addFileHeader($fileName)
  178. {
  179. $firstline = false;
  180. $die = "<?php die();?" . ">\n";
  181. $fileSize = filesize($fileName);
  182. $fh = fopen($fileName, 'c+');
  183. $delta = strlen($die);
  184. while(true)
  185. {
  186. $offset = ftell($fh);
  187. $line = fread($fh, 1024 * 1024);
  188. if(!$firstline)
  189. {
  190. $line = $die . $line;
  191. $firstline = true;
  192. }
  193. else
  194. {
  195. $line = $compensate . $line;
  196. }
  197. $compensate = fread($fh, $delta);
  198. fseek($fh, $offset);
  199. fwrite($fh, $line);
  200. if(ftell($fh) >= $fileSize)
  201. {
  202. fwrite($fh, $compensate);
  203. break;
  204. }
  205. }
  206. fclose($fh);
  207. return true;
  208. }
  209. /**
  210. * Remove file header.
  211. *
  212. * @param string $fileName
  213. * @access public
  214. * @return bool
  215. */
  216. public function removeFileHeader($fileName)
  217. {
  218. $firstline = false;
  219. $die = "<?php die();?" . ">\n";
  220. $fileSize = filesize($fileName);
  221. $fh = fopen($fileName, 'c+');
  222. while(true)
  223. {
  224. $offset = ftell($fh);
  225. if($firstline and $delta) fseek($fh, $offset + $delta);
  226. $line = fread($fh, 1024 * 1024);
  227. if(!$firstline)
  228. {
  229. $firstline = true;
  230. $beforeLength = strlen($line);
  231. $line = str_replace($die, '', $line);
  232. $afterLength = strlen($line);
  233. $delta = $beforeLength - $afterLength;
  234. if($delta == 0)
  235. {
  236. fclose($fh);
  237. return true;
  238. }
  239. }
  240. fseek($fh, $offset);
  241. fwrite($fh, $line);
  242. if(ftell($fh) >= $fileSize - $delta) break;
  243. }
  244. ftruncate($fh, ($fileSize - $delta));
  245. fclose($fh);
  246. return true;
  247. }
  248. /**
  249. * Get dir size.
  250. *
  251. * @param string $backup
  252. * @access public
  253. * @return int
  254. */
  255. public function getBackupSummary($backup)
  256. {
  257. $zfile = $this->app->loadClass('zfile');
  258. if(is_file($backup))
  259. {
  260. $summary = array();
  261. $summary['allCount'] = 1;
  262. $summary['count'] = 1;
  263. $summary['size'] = $zfile->getFileSize($backup);
  264. return $summary;
  265. }
  266. $summaryFile = dirname($backup) . DS . 'summary';
  267. if(!file_exists($summaryFile)) return array();
  268. $summary = json_decode(file_get_contents(dirname($backup) . DS . 'summary'), 'true');
  269. return isset($summary[basename($backup)]) ? $summary[basename($backup)] : array();
  270. }
  271. /**
  272. * Get backup path.
  273. *
  274. * @access public
  275. * @return string
  276. */
  277. public function getBackupPath()
  278. {
  279. $backupPath = empty($this->config->backup->settingDir) ? $this->app->getTmpRoot() . 'backup' . DS : $this->config->backup->settingDir;
  280. return rtrim(str_replace('\\', '/', $backupPath), '/') . '/';
  281. }
  282. /**
  283. * Get backup file.
  284. *
  285. * @param string $name
  286. * @param string $type
  287. * @access public
  288. * @return string
  289. */
  290. public function getBackupFile($name, $type)
  291. {
  292. $backupPath = $this->getBackupPath();
  293. if($type == 'sql')
  294. {
  295. if(file_exists($backupPath . $name . ".{$type}")) return $backupPath . $name . ".{$type}";
  296. if(file_exists($backupPath . $name . ".{$type}.php")) return $backupPath . $name . ".{$type}.php";
  297. }
  298. else
  299. {
  300. if(file_exists($backupPath . $name . ".{$type}")) return $backupPath . $name . ".{$type}";
  301. if(file_exists($backupPath . $name . ".{$type}.zip")) return $backupPath . $name . ".{$type}.zip";
  302. if(file_exists($backupPath . $name . ".{$type}.zip.php")) return $backupPath . $name . ".{$type}.zip.php";
  303. }
  304. return false;
  305. }
  306. /**
  307. * Get tmp log file.
  308. *
  309. * @param string $backupFile
  310. * @access public
  311. * @return string
  312. */
  313. public function getTmpLogFile($backupFile)
  314. {
  315. $backupDir = dirname($backupFile);
  316. return $backupDir . DS . basename($backupFile) . '.tmp.summary';
  317. }
  318. /**
  319. * Get backup dir progress.
  320. *
  321. * @param string $backup
  322. * @access public
  323. * @return array
  324. */
  325. public function getBackupDirProgress($backup)
  326. {
  327. $tmpLogFile = $this->getTmpLogFile($backup);
  328. if(file_exists($tmpLogFile)) return json_decode(file_get_contents($tmpLogFile), true);
  329. return array();
  330. }
  331. /**
  332. * Process filesize.
  333. *
  334. * @param int $fileSize
  335. * @access public
  336. * @return string
  337. */
  338. public function processFileSize($fileSize)
  339. {
  340. $bit = 'KB';
  341. $fileSize = round($fileSize / 1024, 2);
  342. if($fileSize >= 1024)
  343. {
  344. $bit = 'MB';
  345. $fileSize = round($fileSize / 1024, 2);
  346. }
  347. if($fileSize >= 1024)
  348. {
  349. $bit = 'GB';
  350. $fileSize = round($fileSize / 1024, 2);
  351. }
  352. return $fileSize . $bit;
  353. }
  354. /**
  355. * Process backup summary.
  356. *
  357. * @param string $file
  358. * @param int $count
  359. * @param int $size
  360. * @param array $errorFiles
  361. * @param int $allCount
  362. * @param string $action add|delete
  363. * @access public
  364. * @return bool
  365. */
  366. public function processSummary($file, $count, $size, $errorFiles = array(), $allCount = 0, $action = 'add')
  367. {
  368. $backupPath = dirname($file);
  369. $fileName = basename($file);
  370. $summaryFile = $backupPath . DS . 'summary';
  371. if(!file_exists($summaryFile) and !touch($summaryFile)) return false;
  372. $summary = json_decode(file_get_contents($summaryFile), true);
  373. if(empty($summary)) $summary = array();
  374. if($action == 'add')
  375. {
  376. $summary[$fileName]['allCount'] = $allCount;
  377. $summary[$fileName]['errorFiles'] = $errorFiles;
  378. $summary[$fileName]['count'] = $count;
  379. $summary[$fileName]['size'] = $size;
  380. }
  381. else
  382. {
  383. unset($summary[$fileName]);
  384. }
  385. if(file_put_contents($summaryFile, json_encode($summary))) return true;
  386. return false;
  387. }
  388. }