PageRenderTime 66ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/tools/install/cashmusic_web_installer.php

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