PageRenderTime 70ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/updater/classes/Patch.class.php

https://github.com/supungs/AContent
PHP | 805 lines | 457 code | 134 blank | 214 comment | 91 complexity | c387b9763a985ed530b287b39acbd3a0 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, MIT, AGPL-1.0
  1. <?php
  2. /************************************************************************/
  3. /* AContent */
  4. /************************************************************************/
  5. /* Copyright (c) 2010 */
  6. /* Inclusive Design Institute */
  7. /* */
  8. /* This program is free software. You can redistribute it and/or */
  9. /* modify it under the terms of the GNU General Public License */
  10. /* as published by the Free Software Foundation. */
  11. /************************************************************************/
  12. /**
  13. * Patch
  14. * Class for patch installation
  15. * @access public
  16. * @author Cindy Qi Li
  17. * @package Patch
  18. */
  19. define('TR_INCLUDE_PATH', '../../');
  20. require_once(TR_INCLUDE_PATH. "classes/DAO/PatchesDAO.class.php");
  21. require_once(TR_INCLUDE_PATH. "classes/DAO/PatchesFilesDAO.class.php");
  22. require_once(TR_INCLUDE_PATH. "classes/DAO/PatchesFilesActionsDAO.class.php");
  23. class Patch {
  24. // all private
  25. var $patch_array = array(); // the patch data
  26. var $patch_summary_array = array(); // patch summary information
  27. var $patch_id; // current patches.patches_id
  28. var $patch_file_id; // current patches_files.patches_files_id
  29. var $need_access_to_folders = array();// folders that need to have write permission
  30. var $need_access_to_files = array(); // files that need to have write permission
  31. var $backup_files = array(); // backup files
  32. var $patch_files = array(); // patch files
  33. var $errors = array(); // error messages
  34. var $baseURL; // patch folder at UPDATE_SERVER (defined in include/constants.inc.php)
  35. var $backup_suffix; // suffix appended for backup files
  36. var $patch_suffix; // suffix appended for patch files copied from UPDATE_SERVER (defined in include/constants.inc.php)
  37. var $skipFilesModified = false; // if set to true, report error for files that have been modified by user
  38. var $module_content_dir; // content folder used to create patch.sql
  39. var $github_server_connected; // flag indicating if can connect to github server, if not, consider all files manipulated by patch as modified
  40. // constant, URL of user's AContent release version in github
  41. var $github_tag_folder = 'https://raw.github.com/atutor/AContent/';
  42. var $github_fetch_tags_url = 'https://api.github.com/repos/atutor/AContent/tags';
  43. var $sql_file = 'patch.sql';
  44. var $relative_to_root = '../'; // relative path from updater/ to root
  45. var $patchesDAO; // DAO for table "patches"
  46. var $patchesFilesDAO; // DAO for table "patches_files"
  47. var $patchesFilesActionsDAO; // DAO for table "patches_files_actions"
  48. /**
  49. * Constructor: Initialize object members
  50. * @access public
  51. * @param $patch_array The name of the file to find charset definition
  52. * $patch_summary_array
  53. * $skipFilesModified
  54. * @author Cindy Qi Li
  55. */
  56. function Patch($patch_array, $patch_summary_array, $skipFilesModified, $patch_folder)
  57. {
  58. // add relative path to move to AContent root folder
  59. for ($i = 0; $i < count($patch_array[files]); $i++)
  60. {
  61. $patch_array[files][$i]['location'] = $this->relative_to_root . $patch_array[files][$i]['location'];
  62. }
  63. $this->patch_array = $patch_array;
  64. $this->patch_summary_array = $patch_summary_array;
  65. $this->baseURL = $patch_folder;
  66. $this ->backup_suffix = $patch_array['system_patch_id'] . ".old";
  67. $this ->patch_suffix = $patch_array['system_patch_id'];
  68. $this->skipFilesModified = $skipFilesModified;
  69. $this->module_content_dir = TR_CONTENT_DIR . "updater";
  70. $this->patchesDAO = new PatchesDAO();
  71. $this->patchesFilesDAO = new PatchesFilesDAO();
  72. $this->patchesFilesActionsDAO = new PatchesFilesActionsDAO();
  73. session_start();
  74. if (!is_array($_SESSION['remove_permission'])) $_SESSION['remove_permission']=array();
  75. }
  76. /**
  77. * Main process to apply patch.
  78. * @access public
  79. * @return true if patch is successfully applied
  80. * false if failed
  81. * @author Cindy Qi Li
  82. */
  83. function applyPatch()
  84. {
  85. global $msg;
  86. // Checks on
  87. // 1. if github server is up. If not, consider all files manipulated by patch as modified
  88. // 2. if the local file is customized by user
  89. // 3. if script has write priviledge on local file/folder
  90. // 4. if dependent patches have been installed
  91. if (!$this->pingDomain($this->github_tag_folder) || !$this->pingDomain($this->github_fetch_tags_url))
  92. {
  93. $msg->addInfo('CANNOT_CONNEC_GITHUB_SERVER');
  94. $msg->printInfos();
  95. $this->github_server_connected = false;
  96. }
  97. else
  98. $this->github_server_connected = true;
  99. if (!$this->checkDependentPatches()) return false;
  100. if (!$this->checkAppliedVersion()) return false;
  101. if (!$this->skipFilesModified && $this->hasFilesModified()) return false;
  102. if (!$this->checkPriviledge()) return false;
  103. // End of check
  104. if (strlen(trim($this->patch_array['sql'])) > 0) $this->runSQL();
  105. // Start applying patch
  106. $this->createPatchesRecord($this->patch_summary_array);
  107. // if no file action defined, update database and return true
  108. if (!is_array($this->patch_array[files]))
  109. {
  110. $updateInfo = array("status"=>"Installed");
  111. $this->patchesDAO->UpdateByArray($this->patch_id, $updateInfo);
  112. return true;
  113. }
  114. foreach ($this->patch_array[files] as $row_num => $patch_file)
  115. {
  116. $this->createPatchesFilesRecord($this->patch_array['files'][$row_num]);
  117. if ($patch_file['action'] == 'alter')
  118. {
  119. $this->alterFile($row_num);
  120. }
  121. else if ($patch_file['action'] == 'add')
  122. {
  123. $this->addFile($row_num);
  124. }
  125. else if ($patch_file['action'] == 'delete')
  126. {
  127. $this->deleteFile($row_num);
  128. }
  129. else if ($patch_file['action'] == 'overwrite')
  130. {
  131. $this->overwriteFile($row_num);
  132. }
  133. }
  134. // if only has backup files info, patch is considered successfully installed
  135. // if has permission to remove, considered partly installed
  136. $updateInfo = array();
  137. if (count($this->backup_files) > 0)
  138. {
  139. foreach($this->backup_files as $backup_file)
  140. $backup_files .= $backup_file. '|';
  141. $updateInfo = array("backup_files"=>mysql_real_escape_string($backup_files));
  142. }
  143. if (count($this->patch_files) > 0)
  144. {
  145. foreach($this->patch_files as $patch_file)
  146. $patch_files .= $patch_file. '|';
  147. $updateInfo = array_merge($updateInfo, array("patch_files"=>mysql_real_escape_string($patch_files)));
  148. }
  149. if (is_array($_SESSION['remove_permission']) && count($_SESSION['remove_permission']))
  150. {
  151. foreach($_SESSION['remove_permission'] as $remove_permission_file)
  152. $remove_permission_files .= $remove_permission_file. '|';
  153. $updateInfo = array_merge($updateInfo, array("remove_permission_files"=>mysql_real_escape_string($remove_permission_files), "status"=>"Partly Installed"));
  154. }
  155. else
  156. {
  157. $updateInfo = array_merge($updateInfo, array("status"=>"Installed"));
  158. }
  159. $this->patchesDAO->UpdateByArray($this->patch_id, $updateInfo);
  160. unset($_SESSION['remove_permission']);
  161. return true;
  162. }
  163. /**
  164. * return patch array
  165. * @access public
  166. * @return patch array
  167. * @author Cindy Qi Li
  168. */
  169. function getPatchArray()
  170. {
  171. return $this->patch_array;
  172. }
  173. /**
  174. * return patch id processed by this object
  175. * @access public
  176. * @return patch id
  177. * @author Cindy Qi Li
  178. */
  179. function getPatchID()
  180. {
  181. return $this->patch_id;
  182. }
  183. /**
  184. * Check if script has write permission to the files and folders that need to be written
  185. * if no permission, warn user to give permission
  186. * @access private
  187. * @return true if there are files or folders that script has no permission
  188. * false if permissions are in place
  189. * @author Cindy Qi Li
  190. */
  191. function checkPriviledge()
  192. {
  193. global $id, $who;
  194. // no file action is defined, return true;
  195. if (!is_array($this->patch_array[files])) return true;
  196. foreach ($this->patch_array[files] as $row_num => $patch_file)
  197. {
  198. $real_location = realpath($patch_file['location']);
  199. if (!is_writable($patch_file['location']) && !in_array($real_location, $this->need_access_to_folders))
  200. {
  201. $this->need_access_to_folders[] = $real_location;
  202. if (!in_array($real_location, $_SESSION['remove_permission']))
  203. $_SESSION['remove_permission'][] = $real_location;
  204. }
  205. if ($patch_file['action'] == 'alter' || $patch_file['action'] == 'delete' || $patch_file['action'] == 'overwrite')
  206. {
  207. $file = $patch_file['location'] . "/" . $patch_file['name'];
  208. $real_file = realpath($file);
  209. if (file_exists($file) && !is_writable($file) && !in_array($real_file, $this->need_access_to_files))
  210. {
  211. $this->need_access_to_files[] = $real_file;
  212. if (!in_array($real_file, $_SESSION['remove_permission']) && $patch_file['action'] <> 'delete')
  213. $_SESSION['remove_permission'][] = $real_file;
  214. }
  215. }
  216. }
  217. if (count($this->need_access_to_folders) > 0 || count($this->need_access_to_files) > 0)
  218. {
  219. $this->errors[] = _AT('grant_write_permission');
  220. foreach($this->need_access_to_folders as $folder)
  221. {
  222. $this->errors[0] .= '<strong>'. $folder . "</strong><br />";
  223. }
  224. foreach($this->need_access_to_files as $file)
  225. {
  226. $this->errors[0] .= '<strong>'. $file . "</strong><br />";
  227. }
  228. $notes = '<form action="'. $_SERVER['PHP_SELF'].'?id='.$id.'&who='. $who .'" method="post" name="skip_files_modified">
  229. <div class="row buttons">
  230. <input type="submit" name="yes" value="'._AT('continue').'" accesskey="y" />
  231. <input type="submit" name="no" value="'. _AT('cancel'). '" />
  232. <input type="hidden" name="install" value="' . $_POST['install'] . '" />
  233. <input type="hidden" name="install_upload" value="' . $_POST['install_upload'] . '" />
  234. <input type="hidden" name="ignore_version" value="' . $_POST['ignore_version'] . '" />
  235. </div>
  236. </form>';
  237. print_errors($this->errors, $notes);
  238. unset($this->errors);
  239. return false;
  240. }
  241. return true;
  242. }
  243. /**
  244. * Check if AContent version is same as "applied version" defined in the patch.
  245. * @access private
  246. * @return true if versions match
  247. * false if versions don't match
  248. * @author Cindy Qi Li
  249. */
  250. function checkAppliedVersion()
  251. {
  252. global $msg;
  253. if ($this->patch_summary_array["applied_version"] <> VERSION)
  254. {
  255. $this->errors[] = _AT("version_not_match", $this->patch_summary_array["applied_version"]);
  256. $notes = '
  257. <form action="'. $_SERVER['PHP_SELF'].'?id='.$_POST['id'].'&who='. $_POST['who'] .'" method="post" name="skip_files_modified">
  258. <div class="row buttons">
  259. <input type="submit" name="ignore_version" value="'._AT('yes').'" accesskey="y" />
  260. <input type="submit" name="not_ignore_version" value="'. _AT('no'). '" />
  261. <input type="hidden" name="install" value="' . $_POST['install'] . '" />
  262. <input type="hidden" name="install_upload" value="' . $_POST['install_upload'] . '" />
  263. </div>
  264. </form>';
  265. print_errors($this->errors, $notes);
  266. unset($this->errors);
  267. return false;
  268. }
  269. return true;
  270. }
  271. /**
  272. * Check if all the dependent patches have been installed.
  273. * @access private
  274. * @return true if all the dependent patches have been installed
  275. * false if any dependent patch has not been installed.
  276. * @author Cindy Qi Li
  277. */
  278. function checkDependentPatches()
  279. {
  280. global $msg;
  281. $dependent_patches_installed = true;
  282. // if no dependent patch defined, return true
  283. if (!is_array($this->patch_summary_array["dependent_patches"])) return true;
  284. foreach($this->patch_summary_array["dependent_patches"] as $num => $dependent_patch)
  285. {
  286. if (!is_patch_installed($dependent_patch))
  287. {
  288. $dependent_patches_installed = false;
  289. $dependent_patches .= $dependent_patch. ", ";
  290. }
  291. }
  292. if (!$dependent_patches_installed)
  293. {
  294. $errors = array('UPDATE_DEPENDENCY', substr($dependent_patches, 0, -2));
  295. $msg->addError($errors);
  296. return false;
  297. }
  298. return true;
  299. }
  300. /**
  301. * Loop thru all the patch files that will be overwitten or altered,
  302. * to find out if they are modified by user. If it's modified, warn user.
  303. * @access private
  304. * @return true if there are files being modified
  305. * false if no file is modified
  306. * @author Cindy Qi Li
  307. */
  308. function hasFilesModified()
  309. {
  310. $overwrite_modified_files = false;
  311. $alter_modified_files = false;
  312. $has_not_exist_files = false;
  313. // no file action is defined, return nothing is modified (false)
  314. if (!is_array($this->patch_array[files])) return false;
  315. foreach ($this->patch_array[files] as $row_num => $patch_file)
  316. {
  317. if ($patch_file["action"]=='alter' || $patch_file["action"]=='overwrite')
  318. {
  319. if (!file_exists($patch_file['location'] . $patch_file['name']))
  320. {
  321. $not_exist_files .= $patch_file['location'] . $patch_file['name'] . '<br />';
  322. $has_not_exist_files = true;
  323. }
  324. else if ($this->isFileModified($patch_file['location'], $patch_file['name']))
  325. {
  326. if ($patch_file['action']=='overwrite')
  327. {
  328. $overwrite_files .= realpath($patch_file['location'] . $patch_file['name']) . '<br />';
  329. $overwrite_modified_files = true;
  330. }
  331. if ($patch_file['action']=='alter')
  332. {
  333. $alter_files .= realpath($patch_file['location'] . $patch_file['name']) . '<br />';
  334. $alter_modified_files = true;
  335. }
  336. }
  337. }
  338. }
  339. if ($has_not_exist_files) $this->errors[] = _AT('update_local_file_not_exist'). $not_exist_files;
  340. if ($overwrite_modified_files) $this->errors[] = _AT('updater_overwrite_modified_files') . $overwrite_files;
  341. if ($alter_modified_files) $this->errors[] = _AT('updater_alter_modified_files') . $alter_files;
  342. if (count($this->errors) > 0)
  343. {
  344. if ($has_not_exist_files)
  345. $notes = '';
  346. else
  347. $notes = '
  348. <form action="'. $_SERVER['PHP_SELF'].'?id='.$_POST['id'].'&who='. $_POST['who'] .'" method="post" name="skip_files_modified">
  349. <div class="row buttons">
  350. <input type="submit" name="yes" value="'._AT('yes').'" accesskey="y" />
  351. <input type="submit" name="no" value="'. _AT('no'). '" />
  352. <input type="hidden" name="install" value="' . $_POST['install'] . '" />
  353. <input type="hidden" name="install_upload" value="' . $_POST['install_upload'] . '" />
  354. <input type="hidden" name="ignore_version" value="' . $_POST['ignore_version'] . '" />
  355. </div>
  356. </form>';
  357. print_errors($this->errors, $notes);
  358. unset($this->errors);
  359. return true;
  360. }
  361. return false;
  362. }
  363. /**
  364. * Compare user's local file with github backup for user's AContent version,
  365. * if different, check table TR_patches_files to see if user's local file
  366. * was altered by previous patch installation. If it is, return false
  367. * (not modified), otherwise, return true (modified).
  368. * @access private
  369. * @param $folder folder of the file to be compared
  370. * $file name of the file to be compared
  371. * @return true if the file is modified
  372. * false if the file is not modified
  373. * @author Cindy Qi Li
  374. */
  375. function isFileModified($folder, $file)
  376. {
  377. global $db;
  378. if (!$this->github_server_connected) return true;
  379. $remote_file = $this->github_tag_folder . $this->getReleaseCommitNum() .
  380. str_replace(substr($this->relative_to_root, 0, -1), '' , $folder) .$file;
  381. $local_file = $folder.$file;
  382. // check if the local file has been modified by user. if it is, don't overwrite
  383. if ($this->compareFiles($remote_file, $local_file) <> 0 && $this->patchesFilesDAO->getNumOfUpdatesOnFile($file) == 0)
  384. {
  385. // check if the file was changed by previous installed patches
  386. return true;
  387. }
  388. return false;
  389. }
  390. /**
  391. * Get the commit hash for the current AContent release
  392. * @access private
  393. */
  394. private function getReleaseCommitNum() {
  395. $releases_json = file_get_contents($this->github_fetch_tags_url);
  396. $release_tags = json_decode($releases_json);
  397. $atutor_tag_name = 'acontent_' . str_replace('.', '_', VERSION);
  398. foreach ($release_tags as $release_obj) {
  399. if ($release_obj->name == $atutor_tag_name) {
  400. return $release_obj->commit->sha;
  401. }
  402. }
  403. return false;
  404. }
  405. /**
  406. * Run SQL defined in patch.xml
  407. * @access private
  408. * @author Cindy Qi Li
  409. */
  410. function runSQL()
  411. {
  412. // run sql
  413. // As sqlutility.class.php reads sql from a file, write sql to module content folder
  414. $patch_sql_file = $this->module_content_dir . '/' . $this->sql_file;
  415. $fp = fopen($patch_sql_file, 'w');
  416. fwrite($fp, trim($this->patch_array['sql']));
  417. fclose($fp);
  418. require(TR_INCLUDE_PATH . 'classes/sqlutility.class.php');
  419. $sqlUtility = new SqlUtility();
  420. $sqlUtility->queryFromFile($patch_sql_file, TABLE_PREFIX);
  421. @unlink($patch_sql_file);
  422. return true;
  423. }
  424. /**
  425. * Copy file from UPDATE_SERVER (defined in include/constants.inc.php) to user's computer
  426. * @access private
  427. * @param $row_num row number of patch record to be processed
  428. * @author Cindy Qi Li
  429. */
  430. function addFile($row_num)
  431. {
  432. $this->copyFile($this->baseURL . preg_replace('/.php$/', '.new', $this->patch_array['files'][$row_num]['name']), $this->patch_array['files'][$row_num]['location'].$this->patch_array['files'][$row_num]['name']);
  433. return true;
  434. }
  435. /**
  436. * Delete file, backup before deletion
  437. * @access private
  438. * @param $row_num row number of patch record to be processed
  439. * @author Cindy Qi Li
  440. */
  441. function deleteFile($row_num)
  442. {
  443. $local_file = $this->patch_array['files'][$row_num]['location'].$this->patch_array['files'][$row_num]['name'];
  444. $backup_file = $local_file . "." . $this->backup_suffix;
  445. if (file_exists($local_file))
  446. {
  447. // move file to backup
  448. $this->copyFile($local_file, $backup_file);
  449. $this->backup_files[] = realpath($backup_file);
  450. @unlink($local_file);
  451. }
  452. return true;
  453. }
  454. /**
  455. * Alter file based on <action_detail>
  456. * If user's local file is modified and user agrees to proceed with applying patch,
  457. * alter user's local file.
  458. * @access private
  459. * @param $row_num row number of patch record to be processed
  460. * @author Cindy Qi Li
  461. */
  462. function alterFile($row_num)
  463. {
  464. $local_file = $this->patch_array['files'][$row_num]['location'].$this->patch_array['files'][$row_num]['name'];
  465. // backup user's file
  466. $backup_file = $local_file . "." . $this->backup_suffix;
  467. // Checking existence of $backup_file is to fix the bug when there are multiple alter/delete actions
  468. // on the same file, the following backups overwrite the first backup which results in the loss of the
  469. // original code.
  470. if (!file_exists($backup_file))
  471. {
  472. $this->copyFile($local_file, $backup_file);
  473. $this->backup_files[] = realpath($backup_file);
  474. }
  475. $local_file_content = file_get_contents($local_file);
  476. // Modify user's file
  477. foreach ($this->patch_array['files'][$row_num]['action_detail'] as $garbage => $alter_file_action)
  478. {
  479. if ($alter_file_action['type'] == 'delete')
  480. $modified_local_file_content = $this->strReplace($alter_file_action['code_from'], '', $local_file_content);
  481. if ($alter_file_action['type'] == 'replace')
  482. $modified_local_file_content = $this->strReplace($alter_file_action['code_from'], $alter_file_action['code_to'], $local_file_content);
  483. // when code_from is not found, add in warning
  484. if ($modified_local_file_content == $local_file_content)
  485. {
  486. for ($i = 0; $i < count($this->backup_files); $i++)
  487. if ($this->backup_files[$i] == realpath($backup_file))
  488. $this->backup_files[$i] .= ' '._AT("chunks_not_found");
  489. }
  490. else
  491. $local_file_content = $modified_local_file_content;
  492. $this->createPatchesFilesActionsRecord($alter_file_action);
  493. }
  494. $fp = fopen($local_file, 'w');
  495. fwrite($fp, $local_file_content);
  496. fclose($fp);
  497. return true;
  498. }
  499. /**
  500. * Fetch file from UPDATE_SERVER (defined in include/constants.inc.php) and overwrite
  501. * user's local file if the local file is not modified
  502. * If user's local file is modified and user agrees to proceed with applying patch,
  503. * copy the new file to user's local for them to merge manually.
  504. * @access private
  505. * @param $row_num row number of patch record to be processed
  506. * @author Cindy Qi Li
  507. */
  508. function overwriteFile($row_num)
  509. {
  510. $local_file = $this->patch_array['files'][$row_num]['location'].$this->patch_array['files'][$row_num]['name'];
  511. $patch_file = $this->baseURL . preg_replace('/.php$/', '.new', $this->patch_array['files'][$row_num]['name']);
  512. // if local file is modified and user agrees to proceed with applying patch,
  513. // copy the new file to user's local for them to merge manually
  514. if ($this->skipFilesModified && $this->isFileModified($this->patch_array['files'][$row_num]['location'], $this->patch_array['files'][$row_num]['name']))
  515. {
  516. $local_patch_file = $local_file . "." . $this->patch_suffix;
  517. $this->copyFile($patch_file, $local_patch_file);
  518. $this->patch_files[] = realpath($local_patch_file);
  519. }
  520. else
  521. {
  522. $backup_file = $local_file . "." . $this->backup_suffix;
  523. // backup user's file
  524. $this->copyFile($local_file, $backup_file);
  525. $this->backup_files[] = realpath($backup_file);
  526. // overwrite user's file
  527. $this->copyFile($patch_file, $local_file);
  528. }
  529. return true;
  530. }
  531. /**
  532. * Copy file $src to $dest. $src can be a local file or a remote file
  533. * @access private
  534. * @param $src location of the source file
  535. * $dest location of the destination file
  536. * @author Cindy Qi Li
  537. */
  538. function copyFile($src, $dest)
  539. {
  540. $content = file_get_contents($src);
  541. $fp = fopen($dest, 'w');
  542. fwrite($fp, $content);
  543. fclose($fp);
  544. return true;
  545. }
  546. /**
  547. * Compare files $src against $dest
  548. * @access private
  549. * @param $src location of the source file
  550. * $dest location of the destination file
  551. * @return Returns < 0 if $src is less than $dest ; > 0 if $src is greater than $dest, and 0 if they are equal.
  552. * @author Cindy Qi Li
  553. */
  554. function compareFiles($remote_file, $src_file)
  555. {
  556. // use preg_replace to delete
  557. // 1. the line starting with // $Id:
  558. // 2. the line starting with $lm = '$LastChangedDate, ending with ;
  559. // These lines are created by SVN. It could be different in different copies of the same file.
  560. $pattern = '/\/\/ \$Id.*\$|\$lm = \'\$LastChangedDate.*;/';
  561. $remote_file_content = preg_replace($pattern, '', file_get_contents($remote_file));
  562. $src_file_content = preg_replace($pattern, '', file_get_contents($src_file));
  563. // if github script does not exist, consider the script is modified
  564. if (!$remote_file_content) return false;
  565. return strcasecmp($remote_file_content, $src_file_content);
  566. }
  567. /**
  568. * Replace single/multiple lines of string.
  569. * This function handles different new line character at windows/unix platform
  570. * @access private
  571. * @param $search String to replace from
  572. * $replace String to replace to
  573. * $subject Subject to be handled
  574. * @return return replaced string, if nothing is replaced, return original subject
  575. * @author Cindy Qi Li
  576. */
  577. function strReplace($search, $replace, $subject)
  578. {
  579. // Note: DO NOT change the order of the array elements.
  580. // "\n\r", "\r\n" must come before "\n", "\r" in the array,
  581. // otherwise, the new line replace underneath would wrongly replace "\n\r" to "\r\r" or "\n\n"
  582. $new_line_array = array("\n\r", "\r\n", "\r", "\n");
  583. foreach ($new_line_array as $new_line)
  584. {
  585. if (preg_match('/'.preg_quote($new_line).'/', $search) > 0) $search_new_lines[] = $new_line;
  586. if (preg_match('/'.preg_quote($new_line).'/', $replace) > 0) $replace_new_lines[] = $new_line;
  587. if (preg_match('/'.preg_quote($new_line).'/', $subject) > 0) $subject_new_lines[] = $new_line;
  588. }
  589. // replace new line chars in $search, $replace, $subject to the last new line in $subject
  590. if (is_array($subject_new_lines)) $new_line_replace_to = array_pop($subject_new_lines);
  591. if ($new_line_replace_to <> '')
  592. {
  593. if (count($search_new_lines) > 0)
  594. foreach ($search_new_lines as $new_line)
  595. if ($new_line <> $new_line_replace_to)
  596. $search = preg_replace('/'.preg_quote($new_line).'/', $new_line_replace_to, $search);
  597. if (count($replace_new_lines) > 0)
  598. foreach ($replace_new_lines as $new_line)
  599. if ($new_line <> $new_line_replace_to)
  600. $replace = preg_replace('/'.preg_quote($new_line).'/', $new_line_replace_to, $replace);
  601. if (count($subject_new_lines) > 0)
  602. foreach ($subject_new_lines as $new_line)
  603. $subject = preg_replace('/'.preg_quote($new_line).'/', $new_line_replace_to, $subject);
  604. }
  605. return preg_replace('/'. preg_quote($search, '/') .'/', $replace, $subject);
  606. }
  607. /**
  608. * Check if the server is down
  609. * @access private
  610. * @param $domain Server Domain
  611. * @return return false if server is down, otherwise, return true
  612. * @author Cindy Qi Li
  613. */
  614. function pingDomain($domain)
  615. {
  616. $file = @fopen ($domain, 'r');
  617. if (!$file)
  618. return false;
  619. return true;
  620. }
  621. /**
  622. * Insert record into table patches
  623. * @access private
  624. * @param $patch_summary_array Patch summary information
  625. * @author Cindy Qi Li
  626. */
  627. function createPatchesRecord($patch_summary_array)
  628. {
  629. $this->patch_id = $this->patchesDAO->Create($patch_summary_array["system_patch_id"],
  630. $patch_summary_array["applied_version"],
  631. $patch_summary_array["patch_folder"],
  632. $patch_summary_array["description"],
  633. $patch_summary_array["available_to"],
  634. $patch_summary_array["sql"],
  635. $patch_summary_array["status"],
  636. '',
  637. '',
  638. '',
  639. $patch_summary_array["author"]);
  640. return true;
  641. }
  642. /**
  643. * Insert record into table patches_files
  644. * @access private
  645. * @param $patch_files_array Patch information
  646. * @author Cindy Qi Li
  647. */
  648. function createPatchesFilesRecord($patch_files_array)
  649. {
  650. $this->patch_file_id = $this->patchesFilesDAO->Create($this->patch_id,
  651. $patch_files_array['action'],
  652. $patch_files_array['name'],
  653. $patch_files_array['location']);
  654. return true;
  655. }
  656. /**
  657. * Insert record into table patches_files_actions
  658. * @access private
  659. * @param $patch_files_actions_array alter file actions and contents
  660. * @author Cindy Qi Li
  661. */
  662. function createPatchesFilesActionsRecord($patch_files_actions_array)
  663. {
  664. $this->patchesFilesActionsDAO->Create($this->patch_file_id,
  665. $patch_files_actions_array['type'],
  666. $patch_files_actions_array['code_from'],
  667. $patch_files_actions_array['code_to']);
  668. return true;
  669. }
  670. }
  671. ?>