PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/installers/php/cashmusic_web_installer.php

https://github.com/letolabs/DIY
PHP | 656 lines | 523 code | 38 blank | 95 comment | 71 complexity | aefadd69874c18abfbacb5c30cf18c67 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * CASH Music Web Installer
  4. *
  5. * This single file acts as a simple HTML5/JS website, downloading and installing
  6. * the latest platform files, configuring the database, setting and environment
  7. * details, and ultimately removing itself and any extra source from the host
  8. * server. (I kind of feel like a jerk making it delete itself.)
  9. *
  10. * Usage: just upload and run.
  11. *
  12. * A NOTE ABOUT SECURITY:
  13. * This file deletes itself for a reason. It clearly opens up some vulnerabilities
  14. * were it to be a public-facing script. Rather than wrestle with sanitizing all
  15. * input we've chosen to use PDO to sanitize the SQL and remove the file when it
  16. * has run its course to avoid additional file edits.
  17. *
  18. *
  19. * @package diy.org.cashmusic
  20. * @author CASH Music
  21. * @link http://cashmusic.org/
  22. *
  23. * Copyright (c) 2011, CASH Music
  24. * Licensed under the Affero General Public License version 3.
  25. * See http://www.gnu.org/licenses/agpl-3.0.html
  26. */
  27. session_start();
  28. $_SESSION['copying'] = false; // we'll use this in the AJAX copy loops later
  29. if (!isset($_SESSION['release_id']) || isset($_GET['origin'])) {
  30. if(isset($_GET['origin'])) {
  31. $_SESSION['release_id'] = $_GET['origin'];
  32. } else {
  33. $_SESSION['release_id'] = 'stable';
  34. }
  35. }
  36. $cash_root_location = false;
  37. // recursive rmdir:
  38. function rrmdir($dir) {
  39. if (is_dir($dir)) {
  40. $objects = scandir($dir);
  41. foreach ($objects as $object) {
  42. if ($object != "." && $object != "..") {
  43. if (filetype($dir."/".$object) == "dir") rrmdir($dir."/".$object); else unlink($dir."/".$object);
  44. }
  45. }
  46. reset($objects);
  47. rmdir($dir);
  48. }
  49. }
  50. function getBaseURL() {
  51. return 'http'.((empty($_SERVER['HTTPS'])&&$_SERVER['SERVER_PORT']!=443)?'':'s')
  52. .'://'.$_SERVER['HTTP_HOST'];
  53. }
  54. function determinedCopy($source,$dest,$retries=4) {
  55. $retries++;
  56. if (!$_SESSION['copying']) {
  57. $_SESSION['copying'] = true;
  58. while($retries > 0) {
  59. if (function_exists('curl_init')) {
  60. $ch = curl_init();
  61. $timeout = 15;
  62. $userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.5; rv:7.0) Gecko/20100101 Firefox/7.0';
  63. @curl_setopt($ch,CURLOPT_URL,$source);
  64. @curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
  65. @curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
  66. @curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
  67. @curl_setopt($ch, CURLOPT_FAILONERROR, true);
  68. @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  69. @curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  70. @curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  71. @curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  72. $destfile = fopen($dest, 'wb');
  73. @curl_setopt($ch, CURLOPT_FILE, $destfile);
  74. if (curl_exec($ch)) {
  75. fclose($destfile);
  76. curl_close($ch);
  77. return true;
  78. } else {
  79. fclose($destfile);
  80. if (file_exists($dest)) {
  81. unlink($dest);
  82. }
  83. curl_close($ch);
  84. sleep(3);
  85. }
  86. } elseif (ini_get('allow_url_fopen')) {
  87. if (@copy($source,$dest)) {
  88. chmod($dest,0755);
  89. $_SESSION['copying'] = false;
  90. return true;
  91. } else {
  92. sleep(1);
  93. }
  94. }
  95. $retries--;
  96. }
  97. $_SESSION['copying'] = false;
  98. return false;
  99. }
  100. }
  101. function findReplaceInFile($filename,$find,$replace) {
  102. if (is_file($filename)) {
  103. $file = file_get_contents($filename);
  104. $file = str_replace($find, $replace, $file);
  105. if (file_put_contents($filename, $file)) {
  106. return true;
  107. } else {
  108. return false;
  109. }
  110. } else {
  111. return false;
  112. }
  113. }
  114. ob_start();
  115. if (!isset($_POST['installstage'])) {
  116. /**
  117. * BASE MARKUP
  118. *
  119. * This is the basic markup file that will push through all of the other
  120. * stages of the installer, all of which will be accessed via AJAX as this
  121. * script reuses itself.
  122. */
  123. ?>
  124. <!DOCTYPE html>
  125. <html>
  126. <head>
  127. <title>Install / CASH Music</title>
  128. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  129. <style type="text/css" />
  130. /* TAG RESETS */
  131. html {margin:0;padding:0;}
  132. 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;}
  133. a {color:#999;text-decoration:none;}
  134. a:hover {text-decoration:underline;color:#000 !important;}
  135. 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;}
  136. img {border:0;}
  137. ul {padding:0.5em 0 0.5em 1.5em;}
  138. p {margin:0 0 1.5em 0;}
  139. h1 {font-size:32px;line-height:1.125em;margin:0;padding:0;}
  140. h2 {font-size:24px;line-height:1.125em;margin:0;padding:0;}
  141. h3 {font-size:1.5em;line-height:1em;margin:20px 0 0 0;padding:0;padding-bottom:0.35em;}
  142. small {font-size:0.85em;line-height:1.25em;}
  143. small a {color:#000 !important;font-weight:bold;}
  144. table {font-size:0.85em;}
  145. /* GENERAL PAGE LAYOUT */
  146. #topstrip {position:absolute;top:0;left:0;width:100%;height:6px;z-index:400;background-color:#000;color:#666;text-align:right;}
  147. .altcopystyle {font:italic 12px/1.5em georgia, times, serif;color:#4d4d4f;}
  148. .fadedtext {color:#9c9ca9 !important;}
  149. .loginlink {font-weight:bold;font-size:2em;}
  150. /* COLORS */
  151. .bgcolor0 {background-color:#999;}
  152. .bgcolor1, div.usecolor1 input.button, div.usecolor1 a.mockbutton {background-color:#df0854;}
  153. .bgcolor2, div.usecolor2 input.button, div.usecolor2 a.mockbutton {background-color:#df9b08;}
  154. .bgcolor3, div.usecolor3 input.button, div.usecolor3 a.mockbutton {background-color:#aacd07;}
  155. .bgcolor4, div.usecolor4 input.button, div.usecolor4 a.mockbutton {background-color:#0891df;}
  156. .bgcolor5, div.usecolor5 input.button, div.usecolor5 a.mockbutton {background-color:#9b08df;}
  157. div.usecolor1 a, h2.usecolor1 {color:#cd074d;}
  158. div.usecolor2 a, h2.usecolor2 {color:#ca8c07;}
  159. div.usecolor3 a, h2.usecolor3 {color:#97b800;}
  160. div.usecolor4 a, h2.usecolor4 {color:#0080c9;}
  161. div.usecolor5 a, h2.usecolor5 {color:#8a00ca;}
  162. a.usecolor0 {color:#999 !important;}
  163. a.usecolor1 {color:#cd074d !important;}
  164. a.usecolor2 {color:#ca8c07 !important;}
  165. a.usecolor3 {color:#97b800 !important;}
  166. a.usecolor4 {color:#0080c9 !important;}
  167. a.usecolor5 {color:#8a00ca !important;}
  168. a.mockbutton {color:#fff !important;font-size:13px;}
  169. a.mockbutton:hover {background-color:#000 !important;text-decoration:none !important;}
  170. div.callout a {font-weight:bold;color:#999;}
  171. div.callout a:hover {font-weight:bold;color:#231F20;}
  172. * a.needsconfirmation:hover {color:#f00 !important;}
  173. /* FORMS */
  174. form span {line-height:2.5em;}
  175. input,textarea,select {font:italic 13px/1.25em georgia, times, serif !important;padding:8px 2% 8px 2%;border:1px solid #dddddf;width:96%;}
  176. input:active, input:focus, textarea:focus {outline:0;border:1px solid #888;}
  177. 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;}
  178. input.button:hover {background-color:#000 !important;color:#fff;}
  179. input.checkorradio {width:auto !important;margin-top:8px;}
  180. 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;}
  181. select option {padding:8px;}
  182. select:active, select:focus {outline:2px solid #ff0;}
  183. label {font-size:11px;text-transform:uppercase;color:#9c9ca9;}
  184. /* PROGRESS BAR */
  185. #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;}
  186. #progressbar {position:absolute;top:0;left:0;width:0;height:30px;color:#fff;background-color:#0080c9;z-index:100;overflow:hidden;}
  187. p.progressamount {position:absolute;top:0;left:0;margin:0;padding:0 0 0 8px;z-index:10;}
  188. /* FOOTER (base code taken from cssstickyfooter.com) */
  189. * {margin-top:0;padding:0;}
  190. html, body, #wrap {height:100%;}
  191. body > #wrap {height:auto;min-height:99%;}
  192. #mainspc {padding-bottom:40px;padding-top:150px;width:400px;margin:0 auto;}
  193. #footer {position:relative;margin-top:-32px;height:36px;color:#babac4;text-align:left;font-size:11px;line-height:1em;clear:both;background-color:transparent;}
  194. #footer p {padding:12px 8px 0px 12px;}
  195. #footer a {color:#babac4;margin-left:24px;}
  196. #footer a:hover {color:#231F20;}
  197. #footer .donatelink {color:#aaa;}
  198. /* ACCESSIBILITY STUFFS */
  199. * a:active, * a:focus, #footer a.donatelink:active, #footer a.donatelink:focus, input.checkorradio:focus, input.checkorradio:active
  200. {outline:2px solid #ff0;background-color:#ff0;color:#000;}
  201. </style>
  202. <link rel="icon" type="image/png" href="https://cashmusic.org/assets/images/icons/cash.png" />
  203. <script src="https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools-yui-compressed.js" type="text/javascript"></script>
  204. <script type="text/javascript">
  205. var currentColor = 1;
  206. var progressIsVisible = false;
  207. function prepPage() {
  208. if (document.id('nextstepform')) {
  209. document.id('nextstepform').addEvent('submit', function(e) {
  210. if (e) { e.stop(); }
  211. var targetEl = document.id('mainspc').removeClass('usecolor'+currentColor);
  212. if (document.id('installstageinput')) {
  213. currentColor = document.id('installstageinput').get('value');
  214. }
  215. var myHTMLRequest = new Request.HTML({onComplete: function(response){
  216. targetEl.addClass('usecolor'+currentColor);
  217. targetEl.empty().adopt(response);
  218. document.id('mainspc').fade('in');
  219. prepPage();
  220. }});
  221. var that = this;
  222. if (document.id('installstagefade')) {
  223. document.id('mainspc').fade('out');
  224. (function(){myHTMLRequest.post(that);}).delay(600);
  225. } else {
  226. myHTMLRequest.post(that);
  227. }
  228. });
  229. }
  230. }
  231. function showProgress(amount) {
  232. if (document.id('progressspc').get('visibility') !== 'visible') {
  233. document.id('progressspc').fade('in');
  234. }
  235. if (amount > 0) {
  236. $$('p.progressamount').each(function(p){
  237. p.set('text',amount + '%');
  238. });
  239. document.id('progressbar').tween('width',Math.floor(400 * (amount / 100)));
  240. }
  241. }
  242. function hideProgress() {
  243. document.id('progressspc').fade('out');
  244. }
  245. window.addEvent('domready',function() {
  246. document.id('progressspc').set('tween', {duration: 45});
  247. prepPage();
  248. });
  249. </script>
  250. </head>
  251. <body>
  252. <div id="topstrip">&nbsp;</div>
  253. <div id="wrap">
  254. <div id="mainspc" class="usecolor1">
  255. <h1>Hello.</h1>
  256. <p>
  257. This is the installer for the CASH Music platform. It will first grab the latest working
  258. version of the platform, install it, then configure the bits and settings.
  259. </p><p>
  260. You'll only need to answer a couple questions, but please run this file in an empty
  261. folder of it's own if you're installing next to a live site. If you have any questions
  262. please see <a href="http://help.cashmusic.org/" target="_blank">help.cashmusic.org</a> for more.
  263. </p>
  264. xo,
  265. <h2><a href="http://cashmusic.org/">CASH Music</a></h2>
  266. <br /><br />
  267. <div class="nextstep">
  268. <div class="altcopystyle fadedtext" style="margin-bottom:6px;">Whenever you're ready:</div>
  269. <form action="" method="post" id="nextstepform">
  270. <input type="hidden" name="installstage" id="installstageinput" value="2" />
  271. <input type="hidden" id="installstagefade" value="1" />
  272. <input type="submit" class="button" value="Start the installing" />
  273. </form>
  274. </div>
  275. </div>
  276. <div id="progressspc"><p class="progressamount">0%</p><div id="progressbar"><p class="progressamount">0%</p></div></div>
  277. </div>
  278. <div id="footer">
  279. <p><b>&copy; 2011 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>
  280. </div>
  281. </body>
  282. </html>
  283. <?php
  284. } else {
  285. /**
  286. * AJAX FUNCTIONALITY (Pretty much all the actual install steps)
  287. *
  288. * Basic output that will replace the initial message in the "mainspc" div above.
  289. */
  290. switch ($_POST['installstage']) {
  291. case "2":
  292. /**
  293. * TEST CAPABILITIES
  294. *
  295. * Rather than hunt through ini settings, etc we're going to perform a couple real-world
  296. * tests to make sure the server can run the install successfully. If not we fail
  297. * gracefully, or at least early. Like I did in 7th grade Spanish.
  298. *
  299. * Possible Errors:
  300. * 1. directory not empty or in-progress
  301. * 2. no write access
  302. * 3. no curl / fopen wrappers
  303. * 4. no PDO support
  304. * 5. no sqlite / sqlite 3 support
  305. */
  306. $all_tests_pass = true;
  307. if (!isset($_SESSION['testshaverun'])) {
  308. $test_error_number = 0;
  309. $test_error_message = '';
  310. // this nested structure is kinda nutty, but you know...also fine / finite
  311. $total_files = scandir(dirname('.'));
  312. $total_file_count = count($total_files);
  313. if ($total_file_count > 3 && !file_exists('./release_profile.json')) {
  314. // 1. test for EITHER empty directory or in-progress install
  315. $all_tests_pass = false;
  316. $test_error_number = 1;
  317. $test_error_message = 'Please run this in an empty directory. I found extra '
  318. . 'files but no CASH manifest...looks like this folder is '
  319. . 'already in use. Detected ' . $total_file_count . ' files.';
  320. } else {
  321. if (!mkdir('./test',0755,true)) {
  322. $all_tests_pass = false;
  323. $test_error_number = 2;
  324. $test_error_message = "Can't create a directory. Kind of need to do that. Sorry.";
  325. } else {
  326. if (!determinedCopy('http://cashmusic.s3.amazonaws.com/releases/'.$_SESSION['release_id'].'/release_profile.json','./test/release_profile.json')) {
  327. $all_tests_pass = false;
  328. $test_error_number = 3;
  329. $test_error_message = "I'm trying to copy files down but it's not working. "
  330. . "This means I can't see the outside word.<br /><br />"
  331. . 'cURL is' . (function_exists('curl_init') ? '' : ' not') . ' installed.<br />'
  332. . 'fopen wrappers are' . (ini_get('allow_url_fopen') ? '' : ' not') . ' enabled.';
  333. } else {
  334. if (!class_exists(PDO)) {
  335. $all_tests_pass = false;
  336. $test_error_number = 4;
  337. $test_error_message = "Couldn't find PDO. This is a required component of PHP that "
  338. . 'is included by default in most builds of PHP — apparently it '
  339. . 'has been turned off.';
  340. } else {
  341. // connect to the new db...will create if not found
  342. try {
  343. $pdo = new PDO ('sqlite:' . dirname('.') . '/test/test.sqlite');
  344. $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  345. chmod(dirname('.') . '/test/test.sqlite',0755);
  346. $pdo->exec('CREATE TABLE test (id INTEGER PRIMARY KEY, testint integer);');
  347. } catch (PDOException $e) {
  348. $all_tests_pass = false;
  349. $test_error_number = 5;
  350. $test_error_message = "Looks like there's no support for sqlite 3. "
  351. . 'The exact error message given was: <br /><br />'
  352. . $e->getMessage();
  353. }
  354. }
  355. }
  356. }
  357. }
  358. // clean up testing mess:
  359. $_SESSION['testshaverun'] = true;
  360. if (is_dir('./test')) {
  361. rrmdir('./test');
  362. }
  363. }
  364. if (!$all_tests_pass) {
  365. echo '<h1>Error #' . $test_error_number . ' </h1>';
  366. echo '<p>' . $test_error_message . '</p>';
  367. } else {
  368. /**
  369. * INSTALL CURRENT SOURCE
  370. *
  371. * Don't even bother checking for git. Set up directories and hit s3 for files,
  372. * looped AJAX delay keeps things running smooth...
  373. */
  374. $source_message = '<h1>Installing.</h1><p>Copying files. '
  375. . 'This should take a couple minutes.</p>'
  376. . '<div class="altcopystyle fadedtext" style="margin-bottom:6px;">Copying files:</div>';
  377. // as long as determinedCopy isn't spinning we can copy files from the repo
  378. if (!$_SESSION['copying']) {
  379. if (!file_exists('./release_profile.json')) {
  380. // create the directory structure: remove any existing source files and re-download
  381. // we'll make a proper update script later.
  382. if (is_dir('./source')) {
  383. rrmdir('./source');
  384. }
  385. if (is_dir('./admin')) {
  386. rrmdir('./admin');
  387. }
  388. if (is_dir('./api')) {
  389. rrmdir('./api');
  390. }
  391. if (is_dir('./public')) {
  392. rrmdir('./public');
  393. }
  394. if (mkdir('./source',0755,true)) {
  395. // get repo from github, strip unnecessary files and write manifest:
  396. if (determinedCopy('http://cashmusic.s3.amazonaws.com/releases/'.$_SESSION['release_id'].'/release_profile.json','./release_profile.json')) {
  397. echo $source_message;
  398. echo '<form action="" method="post" id="nextstepform"><input type="hidden" name="installstage" id="installstageinput" value="2" /></form>';
  399. echo '<script type="text/javascript">showProgress(0);(function(){document.id("nextstepform").fireEvent("submit");}).delay(50);</script>';
  400. }
  401. } else {
  402. echo '<h1>Oh. Shit. Something\'s wrong.</h1>error creating source directory<br />';
  403. }
  404. } else {
  405. // grab our manifest:
  406. $release_profile = json_decode(file_get_contents('./release_profile.json'),true);
  407. $files = $release_profile['blobs'];
  408. $filecount = count($files);
  409. $currentfile = 1;
  410. foreach ($files as $file => $hash) {
  411. if (!file_exists('./source/'.$file)) {
  412. $path = pathinfo($file);
  413. if (!is_dir('./source/'.$path['dirname'])) mkdir('./source/'.$path['dirname'],0755,true);
  414. if (determinedCopy('http://cashmusic.s3.amazonaws.com/releases/'.$_SESSION['release_id'].'/'.$file,'./source/'.$file)) {
  415. echo $source_message;
  416. if ($currentfile != $filecount) {
  417. echo '<form action="" method="post" id="nextstepform"><input type="hidden" name="installstage" id="installstageinput" value="2" /></form>';
  418. echo '<script type="text/javascript">showProgress(' . ceil(100 * ($currentfile / $filecount)) . ');(function(){document.id("nextstepform").fireEvent("submit");}).delay(60);</script>';
  419. } else {
  420. // we're done; remove the manifest file
  421. if (file_exists('./release_profile.json')) {
  422. unlink('./release_profile.json');
  423. }
  424. echo '<form action="" method="post" id="nextstepform"><input type="hidden" id="installstagefade" value="1" /><input type="hidden" name="installstage" id="installstageinput" value="3" /></form>';
  425. echo '<script type="text/javascript">hideProgress();(function(){document.id("nextstepform").fireEvent("submit");}).delay(250);</script>';
  426. }
  427. break;
  428. } else {
  429. echo '<h1>Oh. Shit. Something\'s wrong.</h1>error copying file: ' . (string)$file . '<br />';
  430. break;
  431. }
  432. }
  433. $currentfile = ++$currentfile;
  434. }
  435. }
  436. } else {
  437. echo $source_message;
  438. echo '<form action="" method="post" id="nextstepform"><input type="hidden" name="installstage" id="installstageinput" value="2" /></form>';
  439. echo '<script type="text/javascript">showProgress(0);(function(){document.id("nextstepform").fireEvent("submit");}).delay(250);</script>';
  440. }
  441. }
  442. break;
  443. case "3":
  444. /**
  445. * GET SETTINGS FROM USER
  446. *
  447. * Locations, MySQL, and email address
  448. */
  449. $settings_message = '<h1>Settings.</h1><p>You don\'t want us to just start putting '
  450. . 'files all over the place, do you? The form is auto-loaded with our best guess at a '
  451. . 'location for the core files, but you can put them anywhere.</p> '
  452. . '<p>The core files should ideally be stored somewhere that isn\'t public, '
  453. . 'so if possible keep them outside the www root folder that holds your site files.</p> '
  454. . '<p>While you\'re at it, add an email address and password for the main admin account.'
  455. . ' (<b>Hint:</b> use a real email address so you can reset your password if need be.)</p>';
  456. if (is_dir('./source/')) {
  457. if (!$cash_root_location) {
  458. // if $cash_root_location is not set above make a directory above the root
  459. $cash_root_location = dirname($_SERVER['DOCUMENT_ROOT']) . '/cashmusic';
  460. }
  461. echo $settings_message;
  462. echo '<form action="" method="post" id="nextstepform"><input type="hidden" id="installstagefade" value="1" /><input type="hidden" name="installstage" id="installstageinput" value="4" /> '
  463. . '<h3>Install core files to:</h3><input type="text" name="frameworklocation" value="' . $cash_root_location . '" /> '
  464. . '<h3>Admin email account:</h3><input type="text" name="adminemailaccount" value="admin@' . $_SERVER['SERVER_NAME'] . '" /> '
  465. . '<h3>Admin password:</h3><input type="text" name="adminpassword" value="" /><br /><span class="fadedtext altcopystyle">Password shown to avoid typos, but will be stored with secure encryption.</span><br /> '
  466. . '<br /><br /><div class="altcopystyle fadedtext" style="margin-bottom:6px;">Alright then:</div><input type="submit" class="button" value="Set it all up" /></div> '
  467. . '</form>';
  468. } else {
  469. echo '<h1>Oh. Shit. Something\'s wrong.</h1> No source directory found.<br />';
  470. }
  471. break;
  472. case "4":
  473. /**
  474. * MAKE IT ALL HAPPEN
  475. *
  476. * Edit and move files, write redirects, set up DBs, remove the installer script, party.
  477. */
  478. $admin_dir = rtrim(dirname($_SERVER['REQUEST_URI']),'/') . '/admin';
  479. $user_settings = array(
  480. 'frameworklocation' => (string)$_POST['frameworklocation'],
  481. 'adminemailaccount' => (string)$_POST['adminemailaccount'],
  482. 'adminpassword' => (string)$_POST['adminpassword'],
  483. 'systemsalt' => md5($user_settings['adminemailaccount'] . time())
  484. );
  485. if ($user_settings['frameworklocation']) {
  486. if (!is_dir($user_settings['frameworklocation'])) {
  487. if (!mkdir($user_settings['frameworklocation'],0755,true)) {
  488. echo "<h1>Oh. Shit. Something's wrong.</h1><p>Couldn't create a directory at" . $user_settings['frameworklocation'] . ".</p>";
  489. break;
  490. }
  491. } else {
  492. if (is_dir($user_settings['frameworklocation'] . '/framework')) {
  493. rrmdir($user_settings['frameworklocation'] . '/framework');
  494. //echo 'removed old framework directory at ' . $cash_root_location . '/framework' . '<br />';
  495. }
  496. }
  497. } else {
  498. echo "<h1>Oh. Shit. Something's wrong.</h1><p>No core location specified.</p>";
  499. break;
  500. }
  501. // modify settings files
  502. if (
  503. !findReplaceInFile('./source/interfaces/php/admin/.htaccess','RewriteBase /interfaces/php/admin','RewriteBase ' . $admin_dir) ||
  504. !findReplaceInFile('./source/interfaces/php/admin/constants.php','$cashmusic_root = $root . "/../../../framework/php/cashmusic.php','$cashmusic_root = "' . $user_settings['frameworklocation'] . '/framework/cashmusic.php') ||
  505. !findReplaceInFile('./source/interfaces/php/admin/constants.php','define(\'ADMIN_WWW_BASE_PATH\', \'/interfaces/php/admin','define(\'ADMIN_WWW_BASE_PATH\', \'' . $admin_dir) ||
  506. !findReplaceInFile('./source/interfaces/php/api/controller.php','dirname(__FILE__).\'/../../../framework/php','$cashmusic_root = "' . $user_settings['frameworklocation'] . '/framework') ||
  507. !findReplaceInFile('./source/framework/php/settings/cashmusic_template.ini.php','driver = "mysql','driver = "sqlite') ||
  508. !findReplaceInFile('./source/framework/php/settings/cashmusic_template.ini.php','database = "cashmusic','database = "cashmusic.sqlite') ||
  509. !findReplaceInFile('./source/framework/php/settings/cashmusic_template.ini.php','apilocation = "http://localhost:8888/interfaces/php/api/','apilocation = "' . getBaseURL() . str_replace('/admin', '/api', $admin_dir)) ||
  510. !findReplaceInFile('./source/framework/php/settings/cashmusic_template.ini.php','salt = "I was born of sun beams; Warming up our limbs','salt = "' . $user_settings['systemsalt']) ||
  511. !findReplaceInFile('./source/framework/php/settings/cashmusic_template.ini.php','systememail = "info@cashmusic.org','systememail = "system@' . $_SERVER['SERVER_NAME'])
  512. ) {
  513. echo "<h1>Oh. Shit. Something's wrong.</h1><p>We had trouble editing a few files. Please try again.</p>";
  514. break;
  515. }
  516. // move source files into place
  517. if (
  518. !rename('./source/framework/php/settings/cashmusic_template.ini.php', './source/framework/php/settings/cashmusic.ini.php') ||
  519. !rename('./source/framework/php', $user_settings['frameworklocation'] . '/framework') ||
  520. !rename('./source/interfaces/php/admin', './admin') ||
  521. !rename('./source/interfaces/php/api', './api') ||
  522. !rename('./source/interfaces/php/public', './public')
  523. ) {
  524. echo '<h1>Oh. Shit. Something\'s wrong.</h1> <p>We couldn\'t move files into place. Please make sure you have write access in '
  525. . 'the directory you specified for the core.</p>';
  526. break;
  527. }
  528. // if the directory was never created then create it now
  529. if (!file_exists($user_settings['frameworklocation'] . '/db')) {
  530. mkdir($user_settings['frameworklocation'] . '/db',0755,true);
  531. } else {
  532. // blow away the old sqlite file.
  533. if (file_exists($user_settings['frameworklocation'] . '/db/cashmusic.sqlite')) {
  534. unlink($user_settings['frameworklocation'] . '/db/cashmusic.sqlite');
  535. }
  536. }
  537. // connect to the new db...will create if not found
  538. try {
  539. $pdo = new PDO ('sqlite:' . $user_settings['frameworklocation'] . '/db/cashmusic.sqlite');
  540. $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
  541. } catch (PDOException $e) {
  542. echo '<h1>Oh. Shit. Something\'s wrong.</h1> <p>Couldn\'t connect to the database.</p>';
  543. die();
  544. break;
  545. }
  546. if ($pdo) {
  547. chmod($user_settings['frameworklocation'] . '/db',0755);
  548. chmod($user_settings['frameworklocation'] . '/db/cashmusic.sqlite',0755);
  549. }
  550. // push in all the tables
  551. try {
  552. $pdo->exec(file_get_contents($user_settings['frameworklocation'] . '/framework/settings/sql/cashmusic_db_sqlite.sql'));
  553. } catch (PDOException $e) {
  554. echo '<h1>Oh. Shit. Something\'s wrong.</h1> <p>Couldn\'t create database tables. Files are all in-place, so you can manually edit settings or start over.';
  555. die();
  556. break;
  557. }
  558. $password_hash = hash_hmac('sha256', $user_settings['adminpassword'], $user_settings['systemsalt']);
  559. $data = array(
  560. 'email_address' => $user_settings['adminemailaccount'],
  561. 'password' => $password_hash,
  562. 'is_admin' => true,
  563. 'api_key' => $api_key = hash_hmac('md5', time() . $password_hash . rand(976654,1234567267), $user_settings['systemsalt']) . substr((string) time(),6),
  564. 'api_secret' => hash_hmac('sha256', time() . $password_hash . rand(976654,1234567267), $user_settings['systemsalt']),
  565. 'creation_date' => time()
  566. );
  567. $query = "INSERT INTO people (email_address,password,is_admin,api_key,api_secret,creation_date) VALUES (:email_address,:password,:is_admin,:api_key,:api_secret,:creation_date)";
  568. try {
  569. $q = $pdo->prepare($query);
  570. } catch (PDOException $e) {
  571. echo '<h1>Oh. Shit. Something\'s wrong.</h1> <p>Couldn\'t add the user to the database.</p>';
  572. die();
  573. break;
  574. }
  575. try {
  576. $success = $q->execute($data);
  577. } catch(PDOException $e) {
  578. echo '<h1>Oh. Shit. Something\'s wrong.</h1> <p>Couldn\'t add the user to the database.</p>';
  579. die();
  580. break;
  581. }
  582. // success message
  583. echo '<h1>All done.</h1><p>Okay. Everything is set up, configured, and ready to go. Follow the link below and login with your email.</p>'
  584. . '<p><br /><br /><a href="./admin/" class="loginlink">Click to login</a><br />';
  585. echo '<br /><br /><br /><br /><small class="altcopystyle fadedtext">I feel compelled to point out that in the time it took you to read this, I, your helpful installer script, have deleted '
  586. . 'myself in the name of security. It is a far, far better thing that I do, than I have ever done; it is a far, far better rest that I go to, than I '
  587. . 'have ever known.</small>';
  588. // create an index.php with a redirect to ./admin in the current directory,
  589. // remove the installer and the remaining source directory
  590. if (is_dir('./source')) rrmdir('./source');
  591. if (is_file('./index.php')) unlink('./index.php');
  592. @file_put_contents('./index.php',"<?php header('Location: ./admin/'); ?>");
  593. if (is_file('./cashmusic_web_installer.php')) unlink('./cashmusic_web_installer.php');
  594. break;
  595. default:
  596. 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>";
  597. }
  598. }
  599. ob_end_flush();
  600. ?>