]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - install.php
Merge branch '0.9.x' of git@gitorious.org:laconica/mainline into 0.9.x
[quix0rs-gnu-social.git] / install.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2009, StatusNet, Inc.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 define('INSTALLDIR', dirname(__FILE__));
21
22 $external_libraries=array(
23     array(
24         'name'=>'gettext',
25         'url'=>'http://us.php.net/manual/en/book.gettext.php',
26         'check_function'=>'gettext'
27     ),
28     array(
29         'name'=>'PEAR',
30         'url'=>'http://pear.php.net/',
31         'deb'=>'php-pear',
32         'include'=>'PEAR.php',
33         'check_class'=>'PEAR'
34     ),
35     array(
36         'name'=>'DB',
37         'pear'=>'DB',
38         'url'=>'http://pear.php.net/package/DB',
39         'deb'=>'php-db',
40         'include'=>'DB/common.php',
41         'check_class'=>'DB_common'
42     ),
43     array(
44         'name'=>'DB_DataObject',
45         'pear'=>'DB_DataObject',
46         'url'=>'http://pear.php.net/package/DB_DataObject',
47         'include'=>'DB/DataObject.php',
48         'check_class'=>'DB_DataObject'
49     ),
50     array(
51         'name'=>'Console_Getopt',
52         'pear'=>'Console_Getopt',
53         'url'=>'http://pear.php.net/package/Console_Getopt',
54         'include'=>'Console/Getopt.php',
55         'check_class'=>'Console_Getopt'
56     ),
57     array(
58         'name'=>'Facebook API',
59         'url'=>'http://developers.facebook.com/',
60         'include'=>'facebook/facebook.php',
61         'check_class'=>'Facebook'
62     ),
63     array(
64         'name'=>'htmLawed',
65         'url'=>'http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed',
66         'include'=>'htmLawed/htmLawed.php',
67         'check_function'=>'htmLawed'
68     ),
69     array(
70         'name'=>'HTTP_Request',
71         'pear'=>'HTTP_Request',
72         'url'=>'http://pear.php.net/package/HTTP_Request',
73         'deb'=>'php-http-request',
74         'include'=>'HTTP/Request.php',
75         'check_class'=>'HTTP_Request'
76     ),
77     array(
78         'name'=>'Mail',
79         'pear'=>'Mail',
80         'url'=>'http://pear.php.net/package/Mail',
81         'deb'=>'php-mail',
82         'include'=>'Mail.php',
83         'check_class'=>'Mail'
84     ),
85     array(
86         'name'=>'Mail_mimeDecode',
87         'pear'=>'Mail_mimeDecode',
88         'url'=>'http://pear.php.net/package/Mail_mimeDecode',
89         'deb'=>'php-mail-mimedecode',
90         'include'=>'Mail/mimeDecode.php',
91         'check_class'=>'Mail_mimeDecode'
92     ),
93     array(
94         'name'=>'Mime_Type',
95         'pear'=>'Mime_Type',
96         'url'=>'http://pear.php.net/package/Mime_Type',
97         'include'=>'MIME/Type.php',
98         'check_class'=>'Mime_Type'
99     ),
100     array(
101         'name'=>'Net_URL_Mapper',
102         'pear'=>'Net_URL_Mapper',
103         'url'=>'http://pear.php.net/package/Net_URL_Mapper',
104         'include'=>'Net/URL/Mapper.php',
105         'check_class'=>'Net_URL_Mapper'
106     ),
107     array(
108         'name'=>'Net_Socket',
109         'pear'=>'Net_Socket',
110         'url'=>'http://pear.php.net/package/Net_Socket',
111         'deb'=>'php-net-socket',
112         'include'=>'Net/Socket.php',
113         'check_class'=>'Net_Socket'
114     ),
115     array(
116         'name'=>'Net_SMTP',
117         'pear'=>'Net_SMTP',
118         'url'=>'http://pear.php.net/package/Net_SMTP',
119         'deb'=>'php-net-smtp',
120         'include'=>'Net/SMTP.php',
121         'check_class'=>'Net_SMTP'
122     ),
123     array(
124         'name'=>'Net_URL',
125         'pear'=>'Net_URL',
126         'url'=>'http://pear.php.net/package/Net_URL',
127         'deb'=>'php-net-url',
128         'include'=>'Net/URL.php',
129         'check_class'=>'Net_URL'
130     ),
131     array(
132         'name'=>'Net_URL2',
133         'pear'=>'Net_URL2',
134         'url'=>'http://pear.php.net/package/Net_URL2',
135         'include'=>'Net/URL2.php',
136         'check_class'=>'Net_URL2'
137     ),
138     array(
139         'name'=>'Services_oEmbed',
140         'pear'=>'Services_oEmbed',
141         'url'=>'http://pear.php.net/package/Services_oEmbed',
142         'include'=>'Services/oEmbed.php',
143         'check_class'=>'Services_oEmbed'
144     ),
145     array(
146         'name'=>'Stomp',
147         'url'=>'http://stomp.codehaus.org/PHP',
148         'include'=>'Stomp.php',
149         'check_class'=>'Stomp'
150     ),
151     array(
152         'name'=>'System_Command',
153         'pear'=>'System_Command',
154         'url'=>'http://pear.php.net/package/System_Command',
155         'include'=>'System/Command.php',
156         'check_class'=>'System_Command'
157     ),
158     array(
159         'name'=>'XMPPHP',
160         'url'=>'http://code.google.com/p/xmpphp',
161         'include'=>'XMPPHP/XMPP.php',
162         'check_class'=>'XMPPHP_XMPP'
163     ),
164     array(
165         'name'=>'PHP Markdown',
166         'url'=>'http://www.michelf.com/projects/php-markdown/',
167         'include'=>'markdown.php',
168         'check_class'=>'Markdown_Parser'
169     ),
170     array(
171         'name'=>'OAuth',
172         'url'=>'http://code.google.com/p/oauth-php',
173         'include'=>'OAuth.php',
174         'check_class'=>'OAuthRequest'
175     ),
176     array(
177         'name'=>'Validate',
178         'pear'=>'Validate',
179         'url'=>'http://pear.php.net/package/Validate',
180         'include'=>'Validate.php',
181         'check_class'=>'Validate'
182     )
183 );
184
185 function main()
186 {
187     if (!checkPrereqs())
188     {
189         return;
190     }
191     
192     if( $_GET['checklibs'] ){
193         showLibs();
194     }else{
195         if ($_SERVER['REQUEST_METHOD'] == 'POST') {
196             handlePost();
197         } else {
198             showForm();
199         }
200     }
201 }
202
203 function haveExternalLibrary($external_library)
204 {
205     if(isset($external_library['include']) && ! include_once($external_library['include'])){
206         return false;
207     }
208     if(isset($external_library['check_function']) && ! function_exists($external_library['check_function'])){
209         return false;
210     }
211     if(isset($external_library['check_class']) && ! class_exists($external_library['check_class'])){
212         return false;
213     }
214     return true;
215 }
216
217 function checkPrereqs()
218 {
219         $pass = true;
220
221     if (file_exists(INSTALLDIR.'/config.php')) {
222          ?><p class="error">Config file &quot;config.php&quot; already exists.</p>
223          <?php
224         $pass = false;
225     }
226
227     if (version_compare(PHP_VERSION, '5.2.3', '<')) {
228             ?><p class="error">Require PHP version 5.2.3 or greater.</p><?php
229                     $pass = false;
230     }
231
232     $reqs = array('gd', 'curl',
233                   'xmlwriter', 'mbstring');
234
235     foreach ($reqs as $req) {
236         if (!checkExtension($req)) {
237             ?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php
238                     $pass = false;
239         }
240     }
241     if (!checkExtension('pgsql') && !checkExtension('mysql')) {
242       ?><p class="error">Cannot find mysql or pgsql extension. You need one or the other: <code><?php echo $req; ?></code></p><?php
243                     $pass = false;
244     }
245
246         if (!is_writable(INSTALLDIR)) {
247          ?><p class="error">Cannot write config file to: <code><?php echo INSTALLDIR; ?></code></p>
248                <p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?></code>
249          <?php
250              $pass = false;
251         }
252
253         // Check the subdirs used for file uploads
254         $fileSubdirs = array('avatar', 'background', 'file');
255         foreach ($fileSubdirs as $fileSubdir) {
256                 $fileFullPath = INSTALLDIR."/$fileSubdir/";
257                 if (!is_writable($fileFullPath)) {
258              ?><p class="error">Cannot write <?php echo $fileSubdir; ?> directory: <code><?php echo $fileFullPath; ?></code></p>
259                        <p>On your server, try this command: <code>chmod a+w <?php echo $fileFullPath; ?></code></p>
260              <?php
261                      $pass = false;
262                 }
263         }
264
265         return $pass;
266 }
267
268 function checkExtension($name)
269 {
270     if (!extension_loaded($name)) {
271         if (!@dl($name.'.so')) {
272             return false;
273         }
274     }
275     return true;
276 }
277
278 function showLibs()
279 {
280     global $external_libraries;
281     $present_libraries=array();
282     $absent_libraries=array();
283     foreach($external_libraries as $external_library){
284         if(haveExternalLibrary($external_library)){
285             $present_libraries[]=$external_library;
286         }else{
287             $absent_libraries[]=$external_library;
288         }
289     }
290     echo<<<E_O_T
291     <div class="instructions">
292         <p>Laconica comes bundled with a number of libraries required for the application to work. However, it is best that you use PEAR or you distribution to manage
293         libraries instead, as they tend to provide security updates faster, and may offer improved performance.</p>
294         <p>On Debian based distributions, such as Ubuntu, use a package manager (such as &quot;aptitude&quot;, &quot;apt-get&quot;, and &quot;synaptic&quot;) to install the package listed.</p>
295         <p>On RPM based distributions, such as Red Hat, Fedora, CentOS, Scientific Linux, Yellow Dog Linux and Oracle Enterprise Linux, use a package manager (such as &quot;yum&quot;, &quot;apt-rpm&quot;, and &quot;up2date&quot;) to install the package listed.</p>
296         <p>On servers without a package manager (such as Windows), or if the library is not packaged for your distribution, you can use PHP's PEAR to install the library. Simply run &quot;pear install &lt;name&gt;&quot;.</p>
297     </div>
298     <h2>Absent Libraries</h2>
299     <ul id="absent_libraries">
300 E_O_T;
301     foreach($absent_libraries as $library)
302     {
303         echo '<li>';
304         if($library['url']){
305             echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
306         }else{
307             echo htmlentities($library['name']);
308         }
309         echo '<ul>';
310         if($library['deb']){
311             echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
312         }
313         if($library['rpm']){
314             echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
315         }
316         if($library['pear']){
317             echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
318         }
319         echo '</ul>';
320     }
321     echo<<<E_O_T
322     </ul>
323     <h2>Installed Libraries</h2>
324     <ul id="present_libraries">
325 E_O_T;
326     foreach($present_libraries as $library)
327     {
328         echo '<li>';
329         if($library['url']){
330             echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
331         }else{
332             echo htmlentities($library['name']);
333         }
334         echo '</li>';
335     }
336     echo<<<E_O_T
337     </ul>
338 E_O_T;
339 }
340
341 function showForm()
342 {
343     echo<<<E_O_T
344         </ul>
345     </dd>
346 </dl>
347 <dl id="page_notice" class="system_notice">
348     <dt>Page notice</dt>
349     <dd>
350         <div class="instructions">
351             <p>Enter your database connection information below to initialize the database.</p>
352             <p>Laconica bundles a number of libraries for ease of installation. <a href="?checklibs=true">You can see what bundled libraries you are using, versus what libraries are installed on your server.</a>
353         </div>
354     </dd>
355 </dl>
356 <form method="post" action="install.php" class="form_settings" id="form_install">
357     <fieldset>
358         <legend>Connection settings</legend>
359         <ul class="form_data">
360             <li>
361                 <label for="sitename">Site name</label>
362                 <input type="text" id="sitename" name="sitename" />
363                 <p class="form_guide">The name of your site</p>
364             </li>
365             <li>
366                 <label for="fancy-enable">Fancy URLs</label>
367                 <input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
368                 <input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
369                 <p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
370             </li>
371             <li>
372                 <label for="host">Hostname</label>
373                 <input type="text" id="host" name="host" />
374                 <p class="form_guide">Database hostname</p>
375             </li>
376             <li>
377
378                 <label for="dbtype">Type</label>
379                 <input type="radio" name="dbtype" id="fancy-mysql" value="mysql" checked='checked' /> MySQL<br />
380                 <input type="radio" name="dbtype" id="dbtype-pgsql" value="pgsql" /> PostgreSQL<br />
381                 <p class="form_guide">Database type</p>
382             </li>
383
384             <li>
385                 <label for="database">Name</label>
386                 <input type="text" id="database" name="database" />
387                 <p class="form_guide">Database name</p>
388             </li>
389             <li>
390                 <label for="username">Username</label>
391                 <input type="text" id="username" name="username" />
392                 <p class="form_guide">Database username</p>
393             </li>
394             <li>
395                 <label for="password">Password</label>
396                 <input type="password" id="password" name="password" />
397                 <p class="form_guide">Database password (optional)</p>
398             </li>
399         </ul>
400         <input type="submit" name="submit" class="submit" value="Submit" />
401     </fieldset>
402 </form>
403
404 E_O_T;
405 }
406
407 function updateStatus($status, $error=false)
408 {
409 ?>
410                 <li <?php echo ($error) ? 'class="error"': ''; ?>><?php echo $status;?></li>
411
412 <?php
413 }
414
415 function handlePost()
416 {
417 ?>
418
419 <?php
420     $host     = $_POST['host'];
421     $dbtype   = $_POST['dbtype'];
422     $database = $_POST['database'];
423     $username = $_POST['username'];
424     $password = $_POST['password'];
425     $sitename = $_POST['sitename'];
426     $fancy    = !empty($_POST['fancy']);
427     $server = $_SERVER['HTTP_HOST'];
428     $path = substr(dirname($_SERVER['PHP_SELF']), 1);
429
430 ?>
431     <dl class="system_notice">
432         <dt>Page notice</dt>
433         <dd>
434             <ul>
435 <?php
436         $fail = false;
437
438     if (empty($host)) {
439         updateStatus("No hostname specified.", true);
440                 $fail = true;
441     }
442
443     if (empty($database)) {
444         updateStatus("No database specified.", true);
445                 $fail = true;
446     }
447
448     if (empty($username)) {
449         updateStatus("No username specified.", true);
450                 $fail = true;
451     }
452
453 //     if (empty($password)) {
454 //         updateStatus("No password specified.", true);
455 //              $fail = true;
456 //     }
457
458     if (empty($sitename)) {
459         updateStatus("No sitename specified.", true);
460                 $fail = true;
461     }
462
463     if($fail){
464             showForm();
465         return;
466     }
467
468     // FIXME: use PEAR::DB or PDO instead of our own switch
469
470     switch($dbtype) {
471         case 'mysql':
472             $db = mysql_db_installer($host, $database, $username, $password);
473             break;
474         case 'pgsql':
475             $db = pgsql_db_installer($host, $database, $username, $password);
476             break;
477         default:
478     }
479
480     if (!$db) {
481         // database connection failed, do not move on to create config file.
482         return false;
483     }
484
485     updateStatus("Writing config file...");
486     $res = writeConf($sitename, $server, $path, $fancy, $db);
487
488     if (!$res) {
489         updateStatus("Can't write config file.", true);
490         showForm();
491         return;
492     }
493
494     /*
495         TODO https needs to be considered
496     */
497     $link = "http://".$server.'/'.$path;
498
499     updateStatus("StatusNet has been installed at $link");
500     updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
501 ?>
502
503 <?php
504 }
505
506 function pgsql_db_installer($host, $database, $username, $password) {
507   $connstring = "dbname=$database host=$host user=$username";
508
509   //No password would mean trust authentication used.
510   if (!empty($password)) {
511     $connstring .= " password=$password";
512   }
513   updateStatus("Starting installation...");
514   updateStatus("Checking database...");
515   $conn = pg_connect($connstring);
516
517   if ($conn ===false) {
518     updateStatus("Failed to connect to database: $connstring");
519     showForm();
520     return false;
521   }
522
523   //ensure database encoding is UTF8
524   $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
525   if ($record->server_encoding != 'UTF8') {
526     updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
527     showForm();
528     return false;
529   }
530
531   updateStatus("Running database script...");
532   //wrap in transaction;
533   pg_query($conn, 'BEGIN');
534   $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
535
536   if ($res === false) {
537       updateStatus("Can't run database script.", true);
538       showForm();
539       return false;
540   }
541   foreach (array('sms_carrier' => 'SMS carrier',
542                 'notice_source' => 'notice source',
543                 'foreign_services' => 'foreign service')
544           as $scr => $name) {
545       updateStatus(sprintf("Adding %s data to database...", $name));
546       $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
547       if ($res === false) {
548           updateStatus(sprintf("Can't run %d script.", $name), true);
549           showForm();
550           return false;
551       }
552   }
553   pg_query($conn, 'COMMIT');
554
555   if (empty($password)) {
556     $sqlUrl = "pgsql://$username@$host/$database";
557   }
558   else {
559     $sqlUrl = "pgsql://$username:$password@$host/$database";
560   }
561
562   $db = array('type' => 'pgsql', 'database' => $sqlUrl);
563
564   return $db;
565 }
566
567 function mysql_db_installer($host, $database, $username, $password) {
568   updateStatus("Starting installation...");
569   updateStatus("Checking database...");
570
571   $conn = mysql_connect($host, $username, $password);
572   if (!$conn) {
573       updateStatus("Can't connect to server '$host' as '$username'.", true);
574       showForm();
575       return false;
576   }
577   updateStatus("Changing to database...");
578   $res = mysql_select_db($database, $conn);
579   if (!$res) {
580       updateStatus("Can't change to database.", true);
581       showForm();
582       return false;
583   }
584   updateStatus("Running database script...");
585   $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
586   if ($res === false) {
587       updateStatus("Can't run database script.", true);
588       showForm();
589       return false;
590   }
591   foreach (array('sms_carrier' => 'SMS carrier',
592                 'notice_source' => 'notice source',
593                 'foreign_services' => 'foreign service')
594           as $scr => $name) {
595       updateStatus(sprintf("Adding %s data to database...", $name));
596       $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
597       if ($res === false) {
598           updateStatus(sprintf("Can't run %d script.", $name), true);
599           showForm();
600           return false;
601       }
602   }
603
604       $sqlUrl = "mysqli://$username:$password@$host/$database";
605       $db = array('type' => 'mysql', 'database' => $sqlUrl);
606       return $db;
607 }
608
609 function writeConf($sitename, $server, $path, $fancy, $db)
610 {
611     // assemble configuration file in a string
612     $cfg =  "<?php\n".
613             "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
614
615             // site name
616             "\$config['site']['name'] = '$sitename';\n\n".
617
618             // site location
619             "\$config['site']['server'] = '$server';\n".
620             "\$config['site']['path'] = '$path'; \n\n".
621
622             // checks if fancy URLs are enabled
623             ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
624
625             // database
626             "\$config['db']['database'] = '{$db['database']}';\n\n".
627             ($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
628             "\$config['db']['type'] = '{$db['type']}';\n\n".
629
630             "?>";
631     // write configuration file out to install directory
632     $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
633
634     return $res;
635 }
636
637 function runDbScript($filename, $conn, $type = 'mysql')
638 {
639     $sql = trim(file_get_contents($filename));
640     $stmts = explode(';', $sql);
641     foreach ($stmts as $stmt) {
642         $stmt = trim($stmt);
643         if (!mb_strlen($stmt)) {
644             continue;
645         }
646         // FIXME: use PEAR::DB or PDO instead of our own switch
647         switch ($type) {
648         case 'mysql':
649             $res = mysql_query($stmt, $conn);
650             if ($res === false) {
651                 $error = mysql_error();
652             }
653             break;
654         case 'pgsql':
655             $res = pg_query($conn, $stmt);
656             if ($res === false) {
657                 $error = pg_last_error();
658             }
659             break;
660         default:
661             updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
662         }
663         if ($res === false) {
664             updateStatus("ERROR ($error) for SQL '$stmt'");
665             return $res;
666         }
667     }
668     return true;
669 }
670
671 ?>
672 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
673 <!DOCTYPE html
674 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
675        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
676 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
677     <head>
678         <title>Install StatusNet</title>
679         <link rel="shortcut icon" href="favicon.ico"/>
680         <link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
681         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
682         <!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
683         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
684         <script src="js/jquery.min.js"></script>
685         <script src="js/install.js"></script>
686     </head>
687     <body id="install">
688         <div id="wrap">
689             <div id="header">
690                 <address id="site_contact" class="vcard">
691                     <a class="url home bookmark" href=".">
692                         <img class="logo photo" src="theme/default/logo.png" alt="StatusNet"/>
693                         <span class="fn org">StatusNet</span>
694                     </a>
695                 </address>
696             </div>
697             <div id="core">
698                 <div id="content">
699                     <h1>Install StatusNet</h1>
700 <?php main(); ?>
701                 </div>
702             </div>
703         </div>
704     </body>
705 </html>