]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - install.php
Add library checking page
[quix0rs-gnu-social.git] / install.php
1 <?php
2 /**
3  * Laconica - a distributed open-source microblogging tool
4  * Copyright (C) 2009, Control Yourself, 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     switch($dbtype) {
469         case 'mysql':
470             $db = mysql_db_installer($host, $database, $username, $password);
471             break;
472         case 'pgsql':
473             $db = pgsql_db_installer($host, $database, $username, $password);
474             break;
475         default:
476     }
477     
478     if (!$db) {
479         // database connection failed, do not move on to create config file.
480         return false;
481     }
482     
483     updateStatus("Writing config file...");
484     $res = writeConf($sitename, $server, $path, $fancy, $db);
485     
486     if (!$res) {
487         updateStatus("Can't write config file.", true);
488         showForm();
489         return;
490     }
491     
492     /*
493         TODO https needs to be considered
494     */
495     $link = "http://".$server.'/'.$path;
496     
497     updateStatus("Laconica has been installed at $link");
498     updateStatus("You can visit your <a href='$link'>new Laconica site</a>.");
499 ?>
500
501 <?php
502 }
503
504 function pgsql_db_installer($host, $database, $username, $password) {
505   $connstring = "dbname=$database host=$host user=$username";
506
507   //No password would mean trust authentication used.
508   if (!empty($password)) {
509     $connstring .= " password=$password";
510   }
511   updateStatus("Starting installation...");
512   updateStatus("Checking database...");
513   $conn = pg_connect($connstring);
514   
515   if ($conn ===false) {
516     updateStatus("Failed to connect to database: $connstring");
517     showForm();
518     return false;
519   }
520
521   //ensure database encoding is UTF8
522   $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
523   if ($record->server_encoding != 'UTF8') {
524     updateStatus("Laconica requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
525     showForm();
526     return false;
527   }
528
529   updateStatus("Running database script...");
530   //wrap in transaction;
531   pg_query($conn, 'BEGIN');
532   $res = runDbScript(INSTALLDIR.'/db/laconica_pg.sql', $conn, 'pgsql');
533   
534   if ($res === false) {
535       updateStatus("Can't run database script.", true);
536       showForm();
537       return false;
538   }
539   foreach (array('sms_carrier' => 'SMS carrier',
540                 'notice_source' => 'notice source',
541                 'foreign_services' => 'foreign service')
542           as $scr => $name) {
543       updateStatus(sprintf("Adding %s data to database...", $name));
544       $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
545       if ($res === false) {
546           updateStatus(sprintf("Can't run %d script.", $name), true);
547           showForm();
548           return false;
549       }
550   }
551   pg_query($conn, 'COMMIT');
552
553   if (empty($password)) {
554     $sqlUrl = "pgsql://$username@$host/$database";
555   }
556   else {
557     $sqlUrl = "pgsql://$username:$password@$host/$database";
558   }
559   
560   $db = array('type' => 'pgsql', 'database' => $sqlUrl);
561   
562   return $db;
563 }
564
565 function mysql_db_installer($host, $database, $username, $password) {
566   updateStatus("Starting installation...");
567   updateStatus("Checking database...");
568
569   $conn = mysql_connect($host, $username, $password);
570   if (!$conn) {
571       updateStatus("Can't connect to server '$host' as '$username'.", true);
572       showForm();
573       return false;
574   }
575   updateStatus("Changing to database...");
576   $res = mysql_select_db($database, $conn);
577   if (!$res) {
578       updateStatus("Can't change to database.", true);
579       showForm();
580       return false;
581   }
582   updateStatus("Running database script...");
583   $res = runDbScript(INSTALLDIR.'/db/laconica.sql', $conn);
584   if ($res === false) {
585       updateStatus("Can't run database script.", true);
586       showForm();
587       return false;
588   }
589   foreach (array('sms_carrier' => 'SMS carrier',
590                 'notice_source' => 'notice source',
591                 'foreign_services' => 'foreign service')
592           as $scr => $name) {
593       updateStatus(sprintf("Adding %s data to database...", $name));
594       $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
595       if ($res === false) {
596           updateStatus(sprintf("Can't run %d script.", $name), true);
597           showForm();
598           return false;
599       }
600   }
601       
602       $sqlUrl = "mysqli://$username:$password@$host/$database";
603       $db = array('type' => 'mysql', 'database' => $sqlUrl);
604       return $db;
605 }
606
607 function writeConf($sitename, $server, $path, $fancy, $db)
608 {
609     // assemble configuration file in a string
610     $cfg =  "<?php\n".
611             "if (!defined('LACONICA')) { exit(1); }\n\n".
612             
613             // site name
614             "\$config['site']['name'] = '$sitename';\n\n".
615             
616             // site location
617             "\$config['site']['server'] = '$server';\n".
618             "\$config['site']['path'] = '$path'; \n\n".
619             
620             // checks if fancy URLs are enabled
621             ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
622             
623             // database
624             "\$config['db']['database'] = '{$db['database']}';\n\n".
625             ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
626             "\$config['db']['type'] = '{$db['type']}';\n\n".
627             
628             "?>";
629     // write configuration file out to install directory
630     $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
631
632     return $res;
633 }
634
635 function runDbScript($filename, $conn, $type = 'mysql')
636 {
637     $sql = trim(file_get_contents($filename));
638     $stmts = explode(';', $sql);
639     foreach ($stmts as $stmt) {
640         $stmt = trim($stmt);
641         if (!mb_strlen($stmt)) {
642             continue;
643         }
644         switch ($type) {
645         case 'mysql':
646             $res = mysql_query($stmt, $conn);
647             break;
648         case 'pgsql':
649             $res = pg_query($conn, $stmt);
650             break;
651         default:
652             updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
653         }
654         if ($res === false) {
655             updateStatus("FAILED SQL: $stmt");
656             return $res;
657         }
658     }
659     return true;
660 }
661
662 ?>
663 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
664 <!DOCTYPE html>
665 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
666     <head>
667         <title>Install Laconica</title>
668         <link rel="shortcut icon" href="favicon.ico"/>
669         <link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
670         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
671         <!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
672         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
673         <script src="js/jquery.min.js"></script>
674         <script src="js/install.js"></script>
675     </head>
676     <body id="install">
677         <div id="wrap">
678             <div id="header">
679                 <address id="site_contact" class="vcard">
680                     <a class="url home bookmark" href=".">
681                         <img class="logo photo" src="theme/default/logo.png" alt="Laconica"/>
682                         <span class="fn org">Laconica</span>
683                     </a>
684                 </address>
685             </div>
686             <div id="core">
687                 <div id="content">
688                     <h1>Install Laconica</h1>
689 <?php main(); ?>
690                 </div>
691             </div>
692         </div>
693     </body>
694 </html>