PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/mods/_standard/patcher/classes/PatchCreator.class.php

https://github.com/harriswong/ATutor
PHP | 386 lines | 221 code | 52 blank | 113 comment | 23 complexity | 1c86d97cee3c3359cf08aabe5346720d MD5 | raw file
  1. <?php
  2. /************************************************************************/
  3. /* ATutor */
  4. /************************************************************************/
  5. /* Copyright (c) 2002-2010 */
  6. /* Inclusive Design Institute */
  7. /* http://atutor.ca */
  8. /* */
  9. /* This program is free software. You can redistribute it and/or */
  10. /* modify it under the terms of the GNU General Public License */
  11. /* as published by the Free Software Foundation. */
  12. /************************************************************************/
  13. // $Id$
  14. /**
  15. * Patch
  16. * Class to create a zipped patch package
  17. * zipped patch package contains patch.xml, the files to be added, overwritten
  18. * @access public
  19. * @author Cindy Qi Li
  20. * @package PatchCreator
  21. */
  22. define('AT_INCLUDE_PATH', '../../../../include/');
  23. require_once (AT_INCLUDE_PATH.'vitals.inc.php');
  24. require_once(AT_INCLUDE_PATH. "../mods/_standard/patcher/include/patch_xml_template.inc.php");
  25. class PatchCreator {
  26. // all private
  27. var $patch_info_array = array(); // the patch info data
  28. var $patch_xml_file; // location of patch.xml
  29. var $current_patch_id; // current myown_patches.myown_patch_id
  30. var $version_folder; // version folder. underneath patcher content folder, to hold all patch folders and corresponding upload files
  31. var $patch_folder; // patch folder. underneath version folder, to hold all upload files
  32. /**
  33. * Constructor: Initialize object members
  34. * @author Cindy Qi Li
  35. * @access public
  36. * @param $patch_info_array All information to create a patch. Example:
  37. * Array
  38. * (
  39. * [atutor_patch_id] => Patch001
  40. * [atutor_version_to_apply] => 1.6
  41. * [description] => this is a sample patch info array
  42. * [sql_statement] =>
  43. * [dependent_patches] => Array
  44. * (
  45. * [0] => P2
  46. * [1] => P3
  47. * )
  48. * [files] => Array
  49. * (
  50. * [0] => Array
  51. * (
  52. * [file_name] => script1.php
  53. * [action] => add
  54. * [directory] => admin/
  55. * [upload_tmp_name] => C:\xampp\tmp\php252.tmp
  56. * )
  57. *
  58. * [1] => Array
  59. * (
  60. * [file_name] => script2.php
  61. * [action] => delete
  62. * [directory] => tools/
  63. * )
  64. * )
  65. *
  66. * )
  67. */
  68. function PatchCreator($patch_info_array, $patch_id)
  69. {
  70. // add slashes if magic_quotes_gpc is off
  71. if (!get_magic_quotes_gpc())
  72. {
  73. $patch_info_array["description"] = addslashes($patch_info_array["description"]);
  74. $patch_info_array["sql_statement"] = addslashes($patch_info_array["sql_statement"]);
  75. for ($i = 0; $i < count($patch_info_array["files"]); $i++)
  76. {
  77. $patch_info_array["files"][$i]["directory"] = addslashes($patch_info_array["files"][$i]["directory"]);
  78. $patch_info_array["files"][$i]["upload_tmp_name"] = addslashes($patch_info_array["files"][$i]["upload_tmp_name"]);
  79. $patch_info_array["files"][$i]["code_from"] = addslashes($patch_info_array["files"][$i]["code_from"]);
  80. $patch_info_array["files"][$i]["code_to"] = addslashes($patch_info_array["files"][$i]["code_to"]);
  81. }
  82. }
  83. $this->patch_info_array = $patch_info_array;
  84. $this->current_patch_id = $patch_id;
  85. $this->patch_xml_file = AT_CONTENT_DIR . "patcher/patch.xml";
  86. $this->version_folder = AT_CONTENT_DIR . "patcher/" . str_replace('.', '_', $this->patch_info_array["atutor_version_to_apply"]) . "/";
  87. $this->patch_folder = $this->version_folder . $this->patch_info_array["atutor_patch_id"] . "/";
  88. }
  89. /**
  90. * Create Patch
  91. * @access public
  92. * @return true if created successfully
  93. * false if error happens
  94. * @author Cindy Qi Li
  95. */
  96. function create_patch()
  97. {
  98. // save patch info into database & save uploaded files into content folder
  99. $this->saveInfo();
  100. // create patch.xml into $this->patch_xml_file
  101. $fp = fopen($this->patch_xml_file,'w');
  102. fwrite($fp,$this->createXML());
  103. fclose($fp);
  104. // create zip package and force download
  105. $this->createZIP();
  106. // clean up
  107. unlink($this->patch_xml_file);
  108. return true;
  109. }
  110. /**
  111. * Save patch info into database & save uploaded files into content folder
  112. * @access public
  113. * @return xml string
  114. * @author Cindy Qi Li
  115. */
  116. function saveInfo()
  117. {
  118. global $db;
  119. if ($this->current_patch_id == 0)
  120. {
  121. $sql = "INSERT INTO ".TABLE_PREFIX."myown_patches
  122. (atutor_patch_id,
  123. applied_version,
  124. description,
  125. sql_statement,
  126. status,
  127. last_modified)
  128. VALUES ('".$this->patch_info_array["atutor_patch_id"]."',
  129. '".$this->patch_info_array["atutor_version_to_apply"]."',
  130. '".$this->patch_info_array["description"]."',
  131. '".$this->patch_info_array["sql_statement"]."',
  132. 'Created',
  133. now())";
  134. }
  135. else
  136. {
  137. $sql = "UPDATE ".TABLE_PREFIX."myown_patches
  138. SET atutor_patch_id = '". $this->patch_info_array["atutor_patch_id"] ."',
  139. applied_version = '". $this->patch_info_array["atutor_version_to_apply"] ."',
  140. description = '". $this->patch_info_array["description"] ."',
  141. sql_statement = '". $this->patch_info_array["sql_statement"] ."',
  142. status = 'Created',
  143. last_modified = now()
  144. WHERE myown_patch_id = ". $this->current_patch_id;
  145. }
  146. $result = mysql_query($sql, $db) or die(mysql_error());
  147. if ($this->current_patch_id == 0)
  148. {
  149. $this->current_patch_id = mysql_insert_id();
  150. }
  151. else // delete records for current_patch_id in tables myown_patches_dependent & myown_patches_files
  152. {
  153. $sql = "DELETE FROM ".TABLE_PREFIX."myown_patches_dependent WHERE myown_patch_id = " . $this->current_patch_id;
  154. $result = mysql_query($sql, $db) or die(mysql_error());
  155. $sql = "DELETE FROM ".TABLE_PREFIX."myown_patches_files WHERE myown_patch_id = " . $this->current_patch_id;
  156. $result = mysql_query($sql, $db) or die(mysql_error());
  157. }
  158. // insert records into table myown_patches_dependent
  159. if (is_array($this->patch_info_array["dependent_patches"]))
  160. {
  161. foreach ($this->patch_info_array["dependent_patches"] as $dependent_patch)
  162. {
  163. $sql = "INSERT INTO ".TABLE_PREFIX."myown_patches_dependent
  164. (myown_patch_id,
  165. dependent_patch_id)
  166. VALUES ('".$this->current_patch_id."',
  167. '".$dependent_patch."')";
  168. $result = mysql_query($sql, $db) or die(mysql_error());
  169. }
  170. }
  171. // insert records into table myown_patches_files
  172. if (is_array($this->patch_info_array["files"]))
  173. {
  174. foreach ($this->patch_info_array["files"] as $file_info)
  175. {
  176. if ($file_info["upload_tmp_name"] <> "")
  177. $upload_to = $this->saveFile($file_info);
  178. else
  179. $upload_to = "";
  180. $sql = "INSERT INTO ".TABLE_PREFIX."myown_patches_files
  181. (myown_patch_id,
  182. action,
  183. name,
  184. location,
  185. code_from,
  186. code_to,
  187. uploaded_file)
  188. VALUES ('".$this->current_patch_id."',
  189. '".$file_info["action"]."',
  190. '".$file_info["file_name"]."',
  191. '".$file_info["directory"]."',
  192. '".$file_info["code_from"]."',
  193. '".$file_info["code_to"]."',
  194. '".addslashes($upload_to)."')";
  195. $result = mysql_query($sql, $db) or die(mysql_error());
  196. }
  197. }
  198. }
  199. /**
  200. * Save upload file into content folder
  201. * @access private
  202. * @return xml string
  203. * @author Cindy Qi Li
  204. */
  205. function saveFile($file_info)
  206. {
  207. // mkdir() function cannot create folder recursively, so have to acomplish the creation of patch folder by 2 steps.
  208. if (!file_exists($this->version_folder)) mkdir($this->version_folder);
  209. if (!file_exists($this->patch_folder)) mkdir($this->patch_folder);
  210. $upload_to = $this->patch_folder . $file_info['file_name'];
  211. // copy uploaded file into content folder
  212. copy($file_info["upload_tmp_name"], $upload_to);
  213. return realpath($upload_to);
  214. }
  215. /**
  216. * Create patch.xml.
  217. * @access private
  218. * @return xml string
  219. * @author Cindy Qi Li
  220. */
  221. function createXML()
  222. {
  223. global $patch_xml, $dependent_patch_xml;
  224. global $patch_action_detail_xml, $patch_file_xml;
  225. // generate content of <dependent_patches> section
  226. if (is_array($this->patch_info_array["dependent_patches"]))
  227. {
  228. foreach ($this->patch_info_array["dependent_patches"] as $dependent_patch)
  229. $dependent_patches .= str_replace('{DEPENDENT_PATCH}', $dependent_patch, $dependent_patch_xml);
  230. }
  231. // generate content of <files> section
  232. if (is_array($this->patch_info_array["files"]))
  233. {
  234. foreach ($this->patch_info_array["files"] as $file_info)
  235. {
  236. $action_details = "";
  237. if ($file_info["action"] == "alter")
  238. {
  239. $action_details .= str_replace(array('{TYPE}', '{CODE_FROM}', '{CODE_TO}'),
  240. array('replace',
  241. htmlspecialchars(stripslashes($file_info["code_from"]), ENT_QUOTES),
  242. htmlspecialchars(stripslashes($file_info["code_to"]), ENT_QUOTES)),
  243. $patch_action_detail_xml);
  244. }
  245. $xml_files .= str_replace(array('{ACTION}', '{NAME}', '{LOCATION}', '{ACTION_DETAILS}'),
  246. array($file_info["action"], $file_info["file_name"], $file_info["directory"], $action_details),
  247. $patch_file_xml);
  248. }
  249. }
  250. // generate patch.xml
  251. return str_replace(array('{ATUTOR_PATCH_ID}',
  252. '{APPLIED_VERSION}',
  253. '{DESCRIPTION}',
  254. '{SQL}',
  255. '{DEPENDENT_PATCHES}',
  256. '{FILES}'),
  257. array($this->patch_info_array["atutor_patch_id"],
  258. $this->patch_info_array["atutor_version_to_apply"],
  259. htmlspecialchars(stripslashes($this->htmlNewLine($this->patch_info_array["description"])), ENT_QUOTES),
  260. htmlspecialchars(stripslashes($this->patch_info_array["sql_statement"]), ENT_QUOTES),
  261. $dependent_patches,
  262. $xml_files),
  263. $patch_xml);
  264. }
  265. /**
  266. * Create xml for section <files> in patch.xml.
  267. * @access private
  268. * @return xml string
  269. * @author Cindy Qi Li
  270. */
  271. function createXMLFiles($file_info)
  272. {
  273. $action_details = "";
  274. if ($file_info["action"] == "alter")
  275. {
  276. $action_details .= str_replace(array('{TYPE}', '{CODE_FROM}', '{CODE_TO}'),
  277. array('replace',
  278. htmlspecialchars(stripslashes($file_info["code_from"]), ENT_QUOTES),
  279. htmlspecialchars(stripslashes($file_info["code_to"]), ENT_QUOTES)),
  280. $patch_action_detail_xml);
  281. }
  282. return str_replace(array('{ACTION}', '{NAME}', '{LOCATION}', '{ACTION_DETAILS}'),
  283. array($file_info["action"], $file_info["file_name"], $file_info["directory"], $action_details),
  284. $patch_file_xml);
  285. }
  286. /**
  287. * Create zip file which contains patch.xml and the files to be added, overwritten, altered; and force to download
  288. * @access private
  289. * @return true if successful
  290. * false if errors
  291. * @author Cindy Qi Li
  292. */
  293. function createZIP()
  294. {
  295. require_once(AT_INCLUDE_PATH . '/classes/zipfile.class.php');
  296. $zipfile = new zipfile();
  297. $zipfile->add_file(file_get_contents($this->patch_xml_file), 'patch.xml');
  298. if (is_array($this->patch_info_array["files"]))
  299. {
  300. foreach ($this->patch_info_array["files"] as $file_info)
  301. {
  302. if ($file_info["upload_tmp_name"] <> '')
  303. {
  304. $file_name = preg_replace('/.php$/', '.new', $file_info['file_name']);
  305. $zipfile->add_file(file_get_contents($file_info['upload_tmp_name']), $file_name);
  306. }
  307. }
  308. }
  309. $zipfile->send_file($this->patch_info_array["atutor_patch_id"]);
  310. }
  311. /**
  312. * replace new line string to html tag <br />
  313. * @access private
  314. * @return converted string
  315. * @author Cindy Qi Li
  316. */
  317. function htmlNewLine($str)
  318. {
  319. $new_line_array = array("\n", "\r", "\n\r", "\r\n");
  320. $found_match = false;
  321. if (strlen(trim($str))==0) return "";
  322. foreach ($new_line_array as $new_line)
  323. if (preg_match('/'.preg_quote($new_line).'/', $str) > 0)
  324. {
  325. $search_new_line = $new_line;
  326. $found_match = true;
  327. }
  328. if ($found_match)
  329. return preg_replace('/'. preg_quote($search_new_line) .'/', "<br />", $str);
  330. else
  331. return $str;
  332. }
  333. }
  334. ?>