PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/installers/php/update/update.php

https://github.com/letolabs/DIY
PHP | 454 lines | 349 code | 39 blank | 66 comment | 79 complexity | 900cad0881c2f332a0a122b4ed8c9997 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * CASH Music Updater
  4. *
  5. * To be launched from within the platform.
  6. *
  7. *
  8. * @package diy.org.cashmusic
  9. * @author CASH Music
  10. * @link http://cashmusic.org/
  11. *
  12. * Copyright (c) 2011, CASH Music
  13. * Licensed under the Affero General Public License version 3.
  14. * See http://www.gnu.org/licenses/agpl-3.0.html
  15. */
  16. session_start();
  17. $_SESSION['copying'] = false; // we'll use this in the AJAX copy loops later
  18. $_SESSION['release_id'] = 'stable';
  19. include_once('./admin/constants.php');
  20. include_once(CASH_PLATFORM_PATH);
  21. $cash_root_location = str_replace('/cashmusic.php','',CASH_PLATFORM_PATH);
  22. // recursive rmdir:
  23. function rrmdir($dir) {
  24. if (is_dir($dir)) {
  25. $objects = scandir($dir);
  26. foreach ($objects as $object) {
  27. if ($object != "." && $object != "..") {
  28. if (filetype($dir."/".$object) == "dir") rrmdir($dir."/".$object); else unlink($dir."/".$object);
  29. }
  30. }
  31. reset($objects);
  32. rmdir($dir);
  33. }
  34. }
  35. function getBaseURL() {
  36. return 'http'.((empty($_SERVER['HTTPS'])&&$_SERVER['SERVER_PORT']!=443)?'':'s')
  37. .'://'.$_SERVER['HTTP_HOST'];
  38. }
  39. function determinedCopy($source,$dest,$retries=4) {
  40. $retries++;
  41. if (!$_SESSION['copying']) {
  42. $_SESSION['copying'] = true;
  43. while($retries > 0) {
  44. if (function_exists('curl_init')) {
  45. $ch = curl_init();
  46. $timeout = 15;
  47. $userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:7.0) Gecko/20100101 Firefox/7.0';
  48. @curl_setopt($ch,CURLOPT_URL,$source);
  49. @curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
  50. @curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
  51. @curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
  52. @curl_setopt($ch, CURLOPT_FAILONERROR, true);
  53. @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  54. @curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  55. @curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  56. @curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  57. $destfile = fopen($dest, 'wb');
  58. @curl_setopt($ch, CURLOPT_FILE, $destfile);
  59. if (curl_exec($ch)) {
  60. fclose($destfile);
  61. curl_close($ch);
  62. return true;
  63. } else {
  64. fclose($destfile);
  65. if (file_exists($dest)) {
  66. unlink($dest);
  67. }
  68. curl_close($ch);
  69. sleep(3);
  70. }
  71. } elseif (ini_get('allow_url_fopen')) {
  72. if (@copy($source,$dest)) {
  73. chmod($dest,0755);
  74. $_SESSION['copying'] = false;
  75. return true;
  76. } else {
  77. sleep(1);
  78. }
  79. }
  80. $retries--;
  81. }
  82. $_SESSION['copying'] = false;
  83. return false;
  84. }
  85. }
  86. function findReplaceInFile($filename,$find,$replace) {
  87. if (is_file($filename)) {
  88. $file = file_get_contents($filename);
  89. $file = str_replace($find, $replace, $file);
  90. if (file_put_contents($filename, $file)) {
  91. return true;
  92. } else {
  93. return false;
  94. }
  95. } else {
  96. return false;
  97. }
  98. }
  99. ob_start();
  100. if (!isset($_POST['installstage'])) {
  101. /**
  102. * BASE MARKUP
  103. *
  104. * This is the basic markup file that will push through all of the other
  105. * stages of the installer, all of which will be accessed via AJAX as this
  106. * script reuses itself.
  107. */
  108. ?>
  109. <!DOCTYPE html>
  110. <html>
  111. <head>
  112. <title>Update / CASH Music</title>
  113. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  114. <style type="text/css" />
  115. /* TAG RESETS */
  116. html {margin:0;padding:0;}
  117. body {color:#231F20;background-color:#fafaf8;text-align:left;font:14px/1.5em "helvetica neue",helvetica,arial,sans-serif;margin:0;padding:0;min-height:300px;min-width:750px;text-rendering:optimizelegibility;}
  118. a {color:#999;text-decoration:none;}
  119. a:hover {text-decoration:underline;color:#000 !important;}
  120. code {display:block;padding:2em;margin:0 0 1.5em 0;background-color:#ddd;background-image:url(../images/currentnav.png);background-position:left top;background-repeat:no-repeat;margin:0 auto;}
  121. img {border:0;}
  122. ul {padding:0.5em 0 0.5em 1.5em;}
  123. p {margin:0 0 1.5em 0;}
  124. h1 {font-size:32px;line-height:1.125em;margin:0;padding:0;}
  125. h2 {font-size:24px;line-height:1.125em;margin:0;padding:0;}
  126. h3 {font-size:1.5em;line-height:1em;margin:20px 0 0 0;padding:0;padding-bottom:0.35em;}
  127. small {font-size:0.85em;line-height:1.25em;}
  128. small a {color:#000 !important;font-weight:bold;}
  129. table {font-size:0.85em;}
  130. /* GENERAL PAGE LAYOUT */
  131. #topstrip {position:absolute;top:0;left:0;width:100%;height:6px;z-index:400;background-color:#000;color:#666;text-align:right;}
  132. .altcopystyle {font:italic 12px/1.5em georgia, times, serif;color:#4d4d4f;}
  133. .fadedtext {color:#9c9ca9 !important;}
  134. /* COLORS */
  135. .bgcolor0 {background-color:#999;}
  136. .bgcolor1, div.usecolor1 input.button, div.usecolor1 a.mockbutton {background-color:#df0854;}
  137. .bgcolor2, div.usecolor2 input.button, div.usecolor2 a.mockbutton {background-color:#df9b08;}
  138. .bgcolor3, div.usecolor3 input.button, div.usecolor3 a.mockbutton {background-color:#aacd07;}
  139. .bgcolor4, div.usecolor4 input.button, div.usecolor4 a.mockbutton {background-color:#0891df;}
  140. .bgcolor5, div.usecolor5 input.button, div.usecolor5 a.mockbutton {background-color:#9b08df;}
  141. div.usecolor1 a, h2.usecolor1 {color:#cd074d;}
  142. div.usecolor2 a, h2.usecolor2 {color:#ca8c07;}
  143. div.usecolor3 a, h2.usecolor3 {color:#97b800;}
  144. div.usecolor4 a, h2.usecolor4 {color:#0080c9;}
  145. div.usecolor5 a, h2.usecolor5 {color:#8a00ca;}
  146. a.usecolor0 {color:#999 !important;}
  147. a.usecolor1 {color:#cd074d !important;}
  148. a.usecolor2 {color:#ca8c07 !important;}
  149. a.usecolor3 {color:#97b800 !important;}
  150. a.usecolor4 {color:#0080c9 !important;}
  151. a.usecolor5 {color:#8a00ca !important;}
  152. a.mockbutton {color:#fff !important;font-size:13px;}
  153. a.mockbutton:hover {background-color:#000 !important;text-decoration:none !important;}
  154. div.callout a {font-weight:bold;color:#999;}
  155. div.callout a:hover {font-weight:bold;color:#231F20;}
  156. * a.needsconfirmation:hover {color:#f00 !important;}
  157. /* FORMS */
  158. form span {line-height:2.5em;}
  159. input,textarea,select {font:italic 13px/1.25em georgia, times, serif !important;padding:8px 2% 8px 2%;border:1px solid #dddddf;width:96%;}
  160. input:active, input:focus, textarea:focus {outline:0;border:1px solid #888;}
  161. input.button, a.mockbutton {background-color:#ccc;padding:8px 18px 8px 18px !important;font:bold 13px/1.25em helvetica,arial,sans-serif !important;cursor:pointer;width:auto !important;border:none;color:#fff;}
  162. input.button:hover {background-color:#000 !important;color:#fff;}
  163. input.checkorradio {width:auto !important;margin-top:8px;}
  164. select {height:34px;line-height:34px;width:100%;padding:8px;border:none;background-color:#ededef;background-image:linear-gradient(top, #dfdfdf 0%, #efefef 100%);background-image:-moz-linear-gradient(top, #dfdfdf 0%, #efefef 100%);border-radius:5px;}
  165. select option {padding:8px;}
  166. select:active, select:focus {outline:2px solid #ff0;}
  167. label {font-size:11px;text-transform:uppercase;color:#9c9ca9;}
  168. /* PROGRESS BAR */
  169. #progressspc {position:relative;width:400px;height:30px;font-size:18px;line-height:30px;font-weight:bold;margin:0 auto;overflow:hidden;color:#eee;background-color:#ccc;visibility:hidden;}
  170. #progressbar {position:absolute;top:0;left:0;width:0;height:30px;color:#fff;background-color:#0080c9;z-index:100;overflow:hidden;}
  171. p.progressamount {position:absolute;top:0;left:0;margin:0;padding:0 0 0 8px;z-index:10;}
  172. /* FOOTER (base code taken from cssstickyfooter.com) */
  173. * {margin-top:0;padding:0;}
  174. html, body, #wrap {height:100%;}
  175. body > #wrap {height:auto;min-height:99%;}
  176. #mainspc {padding-bottom:40px;padding-top:150px;width:400px;margin:0 auto;}
  177. #footer {position:relative;margin-top:-32px;height:36px;color:#babac4;text-align:left;font-size:11px;line-height:1em;clear:both;background-color:transparent;}
  178. #footer p {padding:12px 8px 0px 12px;}
  179. #footer a {color:#babac4;margin-left:24px;}
  180. #footer a:hover {color:#231F20;}
  181. #footer .donatelink {color:#aaa;}
  182. /* ACCESSIBILITY STUFFS */
  183. * a:active, * a:focus, #footer a.donatelink:active, #footer a.donatelink:focus, input.checkorradio:focus, input.checkorradio:active
  184. {outline:2px solid #ff0;background-color:#ff0;color:#000;}
  185. </style>
  186. <link rel="icon" type="image/png" href="https://cashmusic.org/assets/images/icons/cash.png" />
  187. <script src="https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools-yui-compressed.js" type="text/javascript"></script>
  188. <script type="text/javascript">
  189. var currentColor = 1;
  190. var progressIsVisible = false;
  191. function prepPage() {
  192. if (document.id('nextstepform')) {
  193. document.id('nextstepform').addEvent('submit', function(e) {
  194. if (e) { e.stop(); }
  195. var targetEl = document.id('mainspc').removeClass('usecolor'+currentColor);
  196. if (document.id('installstageinput')) {
  197. currentColor = document.id('installstageinput').get('value');
  198. }
  199. var myHTMLRequest = new Request.HTML({onComplete: function(response){
  200. targetEl.addClass('usecolor'+currentColor);
  201. targetEl.empty().adopt(response);
  202. document.id('mainspc').fade('in');
  203. prepPage();
  204. }});
  205. var that = this;
  206. if (document.id('installstagefade')) {
  207. document.id('mainspc').fade('out');
  208. (function(){myHTMLRequest.post(that);}).delay(600);
  209. } else {
  210. myHTMLRequest.post(that);
  211. }
  212. });
  213. }
  214. }
  215. function showProgress(amount) {
  216. if (document.id('progressspc').get('visibility') !== 'visible') {
  217. document.id('progressspc').fade('in');
  218. }
  219. if (amount > 0) {
  220. $$('p.progressamount').each(function(p){
  221. p.set('text',amount + '%');
  222. });
  223. document.id('progressbar').tween('width',Math.floor(400 * (amount / 100)));
  224. }
  225. }
  226. function hideProgress() {
  227. document.id('progressspc').fade('out');
  228. }
  229. window.addEvent('domready',function() {
  230. document.id('progressspc').set('tween', {duration: 45});
  231. prepPage();
  232. });
  233. </script>
  234. </head>
  235. <body>
  236. <div id="topstrip">&nbsp;</div>
  237. <div id="wrap">
  238. <div id="mainspc" class="usecolor1">
  239. <h1>Oh, Hi Again.</h1>
  240. <p>
  241. Upgrading? No worries, it's easy. This script will work a lot like the original
  242. installer. First it'll grab new updates, and download new files. When that's done
  243. it'll swap out your old files for the new and you'll have the latest shiniest things
  244. without losing any data along the way.
  245. </p><p>
  246. As with anything monkeying in your databases, you should back up your current database
  247. now if possible.
  248. </p>
  249. <br /><br />
  250. <div class="nextstep">
  251. <div class="altcopystyle fadedtext" style="margin-bottom:6px;">Whenever you're ready:</div>
  252. <form action="" method="post" id="nextstepform">
  253. <input type="hidden" name="installstage" id="installstageinput" value="2" />
  254. <input type="hidden" id="installstagefade" value="1" />
  255. <input type="submit" class="button" value="Update" />
  256. </form>
  257. </div>
  258. </div>
  259. <div id="progressspc"><p class="progressamount">0%</p><div id="progressbar"><p class="progressamount">0%</p></div></div>
  260. </div>
  261. <div id="footer">
  262. <p><b>&copy; 2012 CASH Music.</b> All our code is open-source. <a href="http://cashmusic.org/why/" style="margin-left:0;">Learn more</a>. <a href="http://help.cashmusic.org/">Get help</a> <a href="http://cashmusic.org/donate" class="donatelink"><b>Donate</b></a></p>
  263. </div>
  264. </body>
  265. </html>
  266. <?php
  267. } else {
  268. /**
  269. * AJAX FUNCTIONALITY (Pretty much all the actual install steps)
  270. *
  271. * Basic output that will replace the initial message in the "mainspc" div above.
  272. */
  273. switch ($_POST['installstage']) {
  274. case "2":
  275. /**
  276. * INSTALL CURRENT SOURCE
  277. *
  278. * Don't even bother checking for git. Set up directories and hit the
  279. * github API, grab the files, looped AJAX delay so we don't make
  280. * anyone at github mad.
  281. */
  282. $source_message = '<h1>Copying files.</h1><p>'
  283. . 'This should take a few minutes.</p>'
  284. . '<div class="altcopystyle fadedtext" style="margin-bottom:6px;">Progress:</div>';
  285. // as long as determinedCopy isn't spinning we can copy files from the repo
  286. if (!$_SESSION['copying']) {
  287. if (!file_exists('./release_profile.json')) {
  288. // create the directory structure: remove any existing source files and re-download
  289. // we'll make a proper update script later.
  290. if (is_dir('./update')) {
  291. rrmdir('./update');
  292. }
  293. if (mkdir('./update',0755,true)) {
  294. // get repo from github, strip unnecessary files and write manifest:
  295. if (determinedCopy('http://cashmusic.s3.amazonaws.com/releases/'.$_SESSION['release_id'].'/release_profile.json','./release_profile.json') && determinedCopy('http://cashmusic.s3.amazonaws.com/releases/'.$_SESSION['release_id'].'/updates.json','./updates.json')) {
  296. echo $source_message;
  297. echo '<form action="" method="post" id="nextstepform"><input type="hidden" name="installstage" id="installstageinput" value="2" /></form>';
  298. echo '<script type="text/javascript">showProgress(0);(function(){document.id("nextstepform").fireEvent("submit");}).delay(50);</script>';
  299. } else {
  300. echo '<h1>Error copying</h1>Could not copy the release profile successfully.<br />';
  301. }
  302. } else {
  303. echo '<h1>Oh. Shit. Something\'s wrong.</h1>error creating source directory<br />';
  304. }
  305. } else {
  306. // grab our manifest:
  307. $files = json_decode(file_get_contents('./release_profile.json'),true);
  308. $updates = json_decode(file_get_contents('./updates.json'),true);
  309. $files = array_merge($files['blobs'],$updates);
  310. $filecount = count($files);
  311. $currentfile = 1;
  312. foreach ($files as $file => $hash) {
  313. if (!file_exists('./update/'.$file)) {
  314. $path = pathinfo($file);
  315. if (!is_dir('./update/'.$path['dirname'])) mkdir('./update/'.$path['dirname'],0755,true);
  316. if (determinedCopy('http://cashmusic.s3.amazonaws.com/releases/'.$_SESSION['release_id'].'/'.$file,'./update/'.$file)) {
  317. echo $source_message;
  318. if ($currentfile != $filecount) {
  319. echo '<form action="" method="post" id="nextstepform"><input type="hidden" name="installstage" id="installstageinput" value="2" /></form>';
  320. echo '<script type="text/javascript">showProgress(' . ceil(100 * ($currentfile / $filecount)) . ');(function(){document.id("nextstepform").fireEvent("submit");}).delay(60);</script>';
  321. } else {
  322. // we're done; remove the manifest file
  323. if (file_exists('./release_profile.json')) {
  324. unlink('./release_profile.json');
  325. }
  326. echo '<form action="" method="post" id="nextstepform"><input type="hidden" id="installstagefade" value="1" /><input type="hidden" name="installstage" id="installstageinput" value="3" /></form>';
  327. echo '<script type="text/javascript">hideProgress();(function(){document.id("nextstepform").fireEvent("submit");}).delay(250);</script>';
  328. }
  329. break;
  330. } else {
  331. echo '<h1>Oh. Shit. Something\'s wrong.</h1>error copying file: ' . $file . '<br />';
  332. break;
  333. }
  334. }
  335. $currentfile = ++$currentfile;
  336. }
  337. }
  338. } else {
  339. echo $source_message;
  340. echo '<form action="" method="post" id="nextstepform"><input type="hidden" name="installstage" id="installstageinput" value="2" /></form>';
  341. echo '<script type="text/javascript">showProgress(0);(function(){document.id("nextstepform").fireEvent("submit");}).delay(250);</script>';
  342. }
  343. break;
  344. case "3":
  345. /**
  346. * MAKE IT ALL HAPPEN
  347. *
  348. * Edit and move files, remove the updated script, party again.
  349. */
  350. $current_version = CASHRequest::$version;
  351. $upgrade_failure = false;
  352. $total_versions_upgraded = 0;
  353. while (is_file('./update/update/updatescripts/' . $current_version . '.php')) {
  354. include('./update/update/updatescripts/' . $current_version . '.php');
  355. if ($upgrade_failure) {
  356. break;
  357. } else {
  358. $current_version++;
  359. $total_versions_upgraded++;
  360. }
  361. }
  362. if (!$upgrade_failure) {
  363. if ($total_versions_upgraded) {
  364. // move source files into place DO NOT OVERWRITE SETTINGS, DUMMY!
  365. if (is_file($cash_root_location . '/cashmusic.php')) unlink($cash_root_location . '/cashmusic.php');
  366. if (is_file('./admin/controller.php')) unlink('./admin/controller.php');
  367. if (is_dir($cash_root_location . '/classes')) rrmdir($cash_root_location . '/classes');
  368. if (is_dir($cash_root_location . '/elements')) rrmdir($cash_root_location . '/elements');
  369. if (is_dir($cash_root_location . '/lib')) rrmdir($cash_root_location . '/lib');
  370. if (is_dir('./admin/assets')) rrmdir('./admin/assets');
  371. if (is_dir('./admin/classes')) rrmdir('./admin/classes');
  372. if (is_dir('./admin/components')) rrmdir('./admin/components');
  373. if (is_dir('./admin/ui')) rrmdir('./admin/ui');
  374. if (is_dir('./api/classes')) rrmdir('./api/classes');
  375. if (is_dir('./public')) rrmdir('./public');
  376. if (
  377. !rename('./update/framework/php/cashmusic.php', $cash_root_location . '/cashmusic.php') ||
  378. !rename('./update/framework/php/classes', $cash_root_location . '/classes') ||
  379. !rename('./update/framework/php/elements', $cash_root_location . '/elements') ||
  380. !rename('./update/framework/php/lib', $cash_root_location . '/lib') ||
  381. !rename('./update/interfaces/php/admin/controller.php', './admin/controller.php') ||
  382. !rename('./update/interfaces/php/admin/assets', './admin/assets') ||
  383. !rename('./update/interfaces/php/admin/classes', './admin/classes') ||
  384. !rename('./update/interfaces/php/admin/components', './admin/components') ||
  385. !rename('./update/interfaces/php/admin/ui', './admin/ui') ||
  386. !rename('./update/interfaces/php/api/classes', './api/classes') ||
  387. !rename('./update/interfaces/php/public', './public')
  388. ) {
  389. echo '<h1>Oh. Shit. Something\'s wrong.</h1> <p>We couldn\'t move files into place. Please make sure you have write access in '
  390. . 'the directory you specified for the core.</p>';
  391. break;
  392. }
  393. // success message
  394. echo '<h1>All done.</h1><p>Okay. You\'re all up-to-date.<br /><br /><a href="./admin/">Back to the admin</a></p>';
  395. echo '<br /><br /><br /><br /><small class="altcopystyle fadedtext">Like last time, I\'m deleting myself. This is going to give me a complex.</small>';
  396. } else {
  397. // error message
  398. echo '<h1>No upgrades performed.</h1><p>Either you are current or we couldn\'t find updates. Your curent version is reported as: ' . $current_version . '</p>';
  399. }
  400. } else {
  401. // error message
  402. echo '<h1>Error converting database.</h1><p>There was a problem updating your database. SQLite databases have been restored and the upgrade has been cancelled. If you were using MySQL you should restore your backup.</p>';
  403. }
  404. // remove the installer and the remaining source directory
  405. if (is_dir('./update')) rrmdir('./update');
  406. if (is_file('./update.php')) unlink('./update.php');
  407. break;
  408. default:
  409. echo "<h1>Oh. Shit. Something's wrong.</h1><p>We ran into an error. Please make sure you have write permissions in this directory and try again.</p>";
  410. }
  411. }
  412. ob_end_flush();
  413. ?>