]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - install.php
Merge branch 'master' into testing
[quix0rs-gnu-social.git] / install.php
1
2 <?php
3 /**
4  * StatusNet - the distributed open-source microblogging tool
5  * Copyright (C) 2009, StatusNet, Inc.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  * @category Installation
21  * @package  Installation
22  *
23  * @author   Adrian Lang <mail@adrianlang.de>
24  * @author   Brenda Wallace <shiny@cpan.org>
25  * @author   Brett Taylor <brett@webfroot.co.nz>
26  * @author   Brion Vibber <brion@pobox.com>
27  * @author   CiaranG <ciaran@ciarang.com>
28  * @author   Craig Andrews <candrews@integralblue.com>
29  * @author   Eric Helgeson <helfire@Erics-MBP.local>
30  * @author   Evan Prodromou <evan@status.net>
31  * @author   Robin Millette <millette@controlyourself.ca>
32  * @author   Sarven Capadisli <csarven@status.net>
33  * @author   Tom Adams <tom@holizz.com>
34  * @author   Zach Copley <zach@status.net>
35  * @license  GNU Affero General Public License http://www.gnu.org/licenses/
36  * @version  0.9.x
37  * @link     http://status.net
38  */
39
40 define('INSTALLDIR', dirname(__FILE__));
41
42 $external_libraries=array(
43     array(
44         'name'=>'gettext',
45         'url'=>'http://us.php.net/manual/en/book.gettext.php',
46         'check_function'=>'gettext'
47     ),
48     array(
49         'name'=>'PEAR',
50         'url'=>'http://pear.php.net/',
51         'deb'=>'php-pear',
52         'include'=>'PEAR.php',
53         'check_class'=>'PEAR'
54     ),
55     array(
56         'name'=>'DB',
57         'pear'=>'DB',
58         'url'=>'http://pear.php.net/package/DB',
59         'deb'=>'php-db',
60         'include'=>'DB/common.php',
61         'check_class'=>'DB_common'
62     ),
63     array(
64         'name'=>'DB_DataObject',
65         'pear'=>'DB_DataObject',
66         'url'=>'http://pear.php.net/package/DB_DataObject',
67         'include'=>'DB/DataObject.php',
68         'check_class'=>'DB_DataObject'
69     ),
70     array(
71         'name'=>'Console_Getopt',
72         'pear'=>'Console_Getopt',
73         'url'=>'http://pear.php.net/package/Console_Getopt',
74         'include'=>'Console/Getopt.php',
75         'check_class'=>'Console_Getopt'
76     ),
77     array(
78         'name'=>'Facebook API',
79         'url'=>'http://developers.facebook.com/',
80         'include'=>'facebook/facebook.php',
81         'check_class'=>'Facebook'
82     ),
83     array(
84         'name'=>'htmLawed',
85         'url'=>'http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed',
86         'include'=>'htmLawed/htmLawed.php',
87         'check_function'=>'htmLawed'
88     ),
89     array(
90         'name'=>'HTTP_Request',
91         'pear'=>'HTTP_Request',
92         'url'=>'http://pear.php.net/package/HTTP_Request',
93         'deb'=>'php-http-request',
94         'include'=>'HTTP/Request.php',
95         'check_class'=>'HTTP_Request'
96     ),
97     array(
98         'name'=>'HTTP_Request2',
99         'pear'=>'HTTP_Request2',
100         'url'=>'http://pear.php.net/package/HTTP_Request2',
101         'include'=>'HTTP/Request2.php',
102         'check_class'=>'HTTP_Request2'
103     ),
104     array(
105         'name'=>'Mail',
106         'pear'=>'Mail',
107         'url'=>'http://pear.php.net/package/Mail',
108         'deb'=>'php-mail',
109         'include'=>'Mail.php',
110         'check_class'=>'Mail'
111     ),
112     array(
113         'name'=>'Mail_mimeDecode',
114         'pear'=>'Mail_mimeDecode',
115         'url'=>'http://pear.php.net/package/Mail_mimeDecode',
116         'deb'=>'php-mail-mimedecode',
117         'include'=>'Mail/mimeDecode.php',
118         'check_class'=>'Mail_mimeDecode'
119     ),
120     array(
121         'name'=>'Mime_Type',
122         'pear'=>'Mime_Type',
123         'url'=>'http://pear.php.net/package/Mime_Type',
124         'include'=>'MIME/Type.php',
125         'check_class'=>'Mime_Type'
126     ),
127     array(
128         'name'=>'Net_URL_Mapper',
129         'pear'=>'Net_URL_Mapper',
130         'url'=>'http://pear.php.net/package/Net_URL_Mapper',
131         'include'=>'Net/URL/Mapper.php',
132         'check_class'=>'Net_URL_Mapper'
133     ),
134     array(
135         'name'=>'Net_LDAP2',
136         'pear'=>'Net_LDAP2',
137         'url'=>'http://pear.php.net/package/Net_LDAP2',
138         'deb'=>'php-net-ldap2',
139         'include'=>'Net/LDAP2.php',
140         'check_class'=>'Net_LDAP2'
141     ),
142     array(
143         'name'=>'Net_Socket',
144         'pear'=>'Net_Socket',
145         'url'=>'http://pear.php.net/package/Net_Socket',
146         'deb'=>'php-net-socket',
147         'include'=>'Net/Socket.php',
148         'check_class'=>'Net_Socket'
149     ),
150     array(
151         'name'=>'Net_SMTP',
152         'pear'=>'Net_SMTP',
153         'url'=>'http://pear.php.net/package/Net_SMTP',
154         'deb'=>'php-net-smtp',
155         'include'=>'Net/SMTP.php',
156         'check_class'=>'Net_SMTP'
157     ),
158     array(
159         'name'=>'Net_URL',
160         'pear'=>'Net_URL',
161         'url'=>'http://pear.php.net/package/Net_URL',
162         'deb'=>'php-net-url',
163         'include'=>'Net/URL.php',
164         'check_class'=>'Net_URL'
165     ),
166     array(
167         'name'=>'Net_URL2',
168         'pear'=>'Net_URL2',
169         'url'=>'http://pear.php.net/package/Net_URL2',
170         'include'=>'Net/URL2.php',
171         'check_class'=>'Net_URL2'
172     ),
173     array(
174         'name'=>'Services_oEmbed',
175         'pear'=>'Services_oEmbed',
176         'url'=>'http://pear.php.net/package/Services_oEmbed',
177         'include'=>'Services/oEmbed.php',
178         'check_class'=>'Services_oEmbed'
179     ),
180     array(
181         'name'=>'Stomp',
182         'url'=>'http://stomp.codehaus.org/PHP',
183         'include'=>'Stomp.php',
184         'check_class'=>'Stomp'
185     ),
186     array(
187         'name'=>'System_Command',
188         'pear'=>'System_Command',
189         'url'=>'http://pear.php.net/package/System_Command',
190         'include'=>'System/Command.php',
191         'check_class'=>'System_Command'
192     ),
193     array(
194         'name'=>'XMPPHP',
195         'url'=>'http://code.google.com/p/xmpphp',
196         'include'=>'XMPPHP/XMPP.php',
197         'check_class'=>'XMPPHP_XMPP'
198     ),
199     array(
200         'name'=>'PHP Markdown',
201         'url'=>'http://www.michelf.com/projects/php-markdown/',
202         'include'=>'markdown.php',
203         'check_class'=>'Markdown_Parser'
204     ),
205     array(
206         'name'=>'OAuth',
207         'url'=>'http://code.google.com/p/oauth-php',
208         'include'=>'OAuth.php',
209         'check_class'=>'OAuthRequest'
210     ),
211     array(
212         'name'=>'Validate',
213         'pear'=>'Validate',
214         'url'=>'http://pear.php.net/package/Validate',
215         'include'=>'Validate.php',
216         'check_class'=>'Validate'
217     )
218 );
219 $dbModules = array(
220     'mysql' => array(
221         'name' => 'MySQL',
222         'check_module' => 'mysql', // mysqli?
223         'installer' => 'mysql_db_installer',
224     ),
225     'pgsql' => array(
226         'name' => 'PostgreSQL',
227         'check_module' => 'pgsql',
228         'installer' => 'pgsql_db_installer',
229     ),
230 );
231
232 /**
233  * the actual installation.
234  * If call libraries are present, then install
235  *
236  * @return void
237  */
238 function main()
239 {
240     if (!checkPrereqs()) {
241         return;
242     }
243
244     if (!empty($_GET['checklibs'])) {
245         showLibs();
246     } else {
247         if ($_SERVER['REQUEST_METHOD'] == 'POST') {
248             handlePost();
249         } else {
250             showForm();
251         }
252     }
253 }
254
255 /**
256  * checks if an external libary is present
257  *
258  * @param string $external_library Name of library
259  *
260  * @return boolean indicates if library present
261  */
262 function haveExternalLibrary($external_library)
263 {
264     if (isset($external_library['include']) && !haveIncludeFile($external_library['include'])) {
265         return false;
266     }
267     if (isset($external_library['check_function']) && ! function_exists($external_library['check_function'])) {
268         return false;
269     }
270     if (isset($external_library['check_class']) && ! class_exists($external_library['check_class'])) {
271         return false;
272     }
273     return true;
274 }
275
276 // Attempt to include a PHP file and report if it worked, while
277 // suppressing the annoying warning messages on failure.
278 function haveIncludeFile($filename) {
279     $old = error_reporting(error_reporting() & ~E_WARNING);
280     $ok = include_once($filename);
281     error_reporting($old);
282     return $ok;
283 }
284
285 /**
286  * Check if all is ready for installation
287  *
288  * @return void
289  */
290 function checkPrereqs()
291 {
292     $pass = true;
293
294     if (file_exists(INSTALLDIR.'/config.php')) {
295          printf('<p class="error">Config file &quot;config.php&quot; already exists.</p>');
296         $pass = false;
297     }
298
299     if (version_compare(PHP_VERSION, '5.2.3', '<')) {
300         printf('<p class="error">Require PHP version 5.2.3 or greater.</p>');
301         $pass = false;
302     }
303
304     $reqs = array('gd', 'curl',
305                   'xmlwriter', 'mbstring', 'xml', 'dom', 'simplexml');
306
307     foreach ($reqs as $req) {
308         if (!checkExtension($req)) {
309             printf('<p class="error">Cannot load required extension: <code>%s</code></p>', $req);
310             $pass = false;
311         }
312     }
313     // Make sure we have at least one database module available
314     global $dbModules;
315     $missingExtensions = array();
316     foreach ($dbModules as $type => $info) {
317         if (!checkExtension($info['check_module'])) {
318             $missingExtensions[] = $info['check_module'];
319         }
320     }
321
322     if (count($missingExtensions) == count($dbModules)) {
323         $req = implode(', ', $missingExtensions);
324         printf('<p class="error">Cannot find mysql or pgsql extension. You need one or the other.');
325         $pass = false;
326     }
327
328     if (!is_writable(INSTALLDIR)) {
329         printf('<p class="error">Cannot write config file to: <code>%s</code></p>', INSTALLDIR);
330         printf('<p>On your server, try this command: <code>chmod a+w %s</code>', INSTALLDIR);
331         $pass = false;
332     }
333
334     // Check the subdirs used for file uploads
335     $fileSubdirs = array('avatar', 'background', 'file');
336     foreach ($fileSubdirs as $fileSubdir) {
337         $fileFullPath = INSTALLDIR."/$fileSubdir/";
338         if (!is_writable($fileFullPath)) {
339             printf('<p class="error">Cannot write to %s directory: <code>%s</code></p>', $fileSubdir, $fileFullPath);
340             printf('<p>On your server, try this command: <code>chmod a+w %s</code></p>', $fileFullPath);
341             $pass = false;
342         }
343     }
344
345     return $pass;
346 }
347
348 /**
349  * Checks if a php extension is both installed and loaded
350  *
351  * @param string $name of extension to check
352  *
353  * @return boolean whether extension is installed and loaded
354  */
355 function checkExtension($name)
356 {
357     if (extension_loaded($name)) {
358         return true;
359     } elseif (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode')) {
360         // dl will throw a fatal error if it's disabled or we're in safe mode.
361         // More fun, it may not even exist under some SAPIs in 5.3.0 or later...
362         $soname = $name . '.' . PHP_SHLIB_SUFFIX;
363         if (PHP_SHLIB_SUFFIX == 'dll') {
364             $soname = "php_" . $soname;
365         }
366         return @dl($soname);
367     } else {
368         return false;
369     }
370 }
371
372 /**
373  * Show list of libraries
374  *
375  * @return void
376  */
377 function showLibs()
378 {
379     global $external_libraries;
380     $present_libraries=array();
381     $absent_libraries=array();
382     foreach ($external_libraries as $external_library) {
383         if (haveExternalLibrary($external_library)) {
384             $present_libraries[]=$external_library;
385         } else {
386             $absent_libraries[]=$external_library;
387         }
388     }
389     echo<<<E_O_T
390     <div class="instructions">
391         <p>StatusNet 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
392         libraries instead, as they tend to provide security updates faster, and may offer improved performance.</p>
393         <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>
394         <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>
395         <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>
396     </div>
397     <h2>Absent Libraries</h2>
398     <ul id="absent_libraries">
399 E_O_T;
400     foreach ($absent_libraries as $library) {
401         echo '<li>';
402         if (isset($library['url'])) {
403             echo '<a href="'.$library['url'].'">'.htmlentities($library['name']).'</a>';
404         } else {
405             echo htmlentities($library['name']);
406         }
407         echo '<ul>';
408         if (isset($library['deb'])) {
409             echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
410         }
411         if (isset($library['rpm'])) {
412             echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
413         }
414         if (isset($library['pear'])) {
415             echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
416         }
417         echo '</ul>';
418     }
419     echo<<<E_O_T
420     </ul>
421     <h2>Installed Libraries</h2>
422     <ul id="present_libraries">
423 E_O_T;
424     foreach ($present_libraries as $library) {
425         echo '<li>';
426         if (isset($library['url'])) {
427             echo '<a href="'.$library['url'].'">'.htmlentities($library['name']).'</a>';
428         } else {
429             echo htmlentities($library['name']);
430         }
431         echo '</li>';
432     }
433     echo<<<E_O_T
434     </ul>
435 E_O_T;
436 }
437
438 /**
439  * Helper class for building form
440  */
441 class Posted {
442     function value($name)
443     {
444         if (isset($_POST[$name])) {
445             return htmlspecialchars(strval($_POST[$name]));
446         } else {
447             return '';
448         }
449     }
450 }
451
452 function showForm()
453 {
454     global $dbModules;
455     $post = new Posted();
456     $dbRadios = '';
457     if (isset($_POST['dbtype'])) {
458         $dbtype = $_POST['dbtype'];
459     } else {
460         $dbtype = null;
461     }
462     foreach ($dbModules as $type => $info) {
463         if (checkExtension($info['check_module'])) {
464             if ($dbtype == null || $dbtype == $type) {
465                 $checked = 'checked="checked" ';
466                 $dbtype = $type; // if we didn't have one checked, hit the first
467             } else {
468                 $checked = '';
469             }
470             $dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
471         }
472     }
473     echo<<<E_O_T
474         </ul>
475     </dd>
476 </dl>
477 <dl id="page_notice" class="system_notice">
478     <dt>Page notice</dt>
479     <dd>
480         <div class="instructions">
481             <p>Enter your database connection information below to initialize the database.</p>
482         </div>
483     </dd>
484 </dl>
485 <form method="post" action="install.php" class="form_settings" id="form_install">
486     <fieldset>
487         <legend>Connection settings</legend>
488         <ul class="form_data">
489             <li>
490                 <label for="sitename">Site name</label>
491                 <input type="text" id="sitename" name="sitename" value="{$post->value('sitename')}" />
492                 <p class="form_guide">The name of your site</p>
493             </li>
494             <li>
495                 <label for="fancy-enable">Fancy URLs</label>
496                 <input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
497                 <input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
498                 <p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
499             </li>
500             <li>
501                 <label for="host">Hostname</label>
502                 <input type="text" id="host" name="host" value="{$post->value('host')}" />
503                 <p class="form_guide">Database hostname</p>
504             </li>
505             <li>
506
507                 <label for="dbtype">Type</label>
508                 $dbRadios
509                 <p class="form_guide">Database type</p>
510             </li>
511
512             <li>
513                 <label for="database">Name</label>
514                 <input type="text" id="database" name="database" value="{$post->value('database')}" />
515                 <p class="form_guide">Database name</p>
516             </li>
517             <li>
518                 <label for="dbusername">DB username</label>
519                 <input type="text" id="dbusername" name="dbusername" value="{$post->value('dbusername')}" />
520                 <p class="form_guide">Database username</p>
521             </li>
522             <li>
523                 <label for="dbpassword">DB password</label>
524                 <input type="password" id="dbpassword" name="dbpassword" value="{$post->value('dbpassword')}" />
525                 <p class="form_guide">Database password (optional)</p>
526             </li>
527             <li>
528                 <label for="admin_nickname">Administrator nickname</label>
529                 <input type="text" id="admin_nickname" name="admin_nickname" value="{$post->value('admin_nickname')}" />
530                 <p class="form_guide">Nickname for the initial StatusNet user (administrator)</p>
531             </li>
532             <li>
533                 <label for="admin_password">Administrator password</label>
534                 <input type="password" id="admin_password" name="admin_password" value="{$post->value('admin_password')}" />
535                 <p class="form_guide">Password for the initial StatusNet user (administrator)</p>
536             </li>
537             <li>
538                 <label for="admin_password2">Confirm password</label>
539                 <input type="password" id="admin_password2" name="admin_password2" value="{$post->value('admin_password2')}" />
540             </li>
541             <li>
542                 <label for="admin_email">Administrator e-mail</label>
543                 <input id="admin_email" name="admin_email" value="{$post->value('admin_email')}" />
544                 <p class="form_guide">Optional email address for the initial StatusNet user (administrator)</p>
545             </li>
546         </ul>
547         <input type="submit" name="submit" class="submit" value="Submit" />
548     </fieldset>
549 </form>
550
551 E_O_T;
552 }
553
554 function updateStatus($status, $error=false)
555 {
556     echo '<li' . ($error ? ' class="error"': '' ) . ">$status</li>";
557 }
558
559 function handlePost()
560 {
561     $host     = $_POST['host'];
562     $dbtype   = $_POST['dbtype'];
563     $database = $_POST['database'];
564     $username = $_POST['dbusername'];
565     $password = $_POST['dbpassword'];
566     $sitename = $_POST['sitename'];
567     $fancy    = !empty($_POST['fancy']);
568
569     $adminNick = $_POST['admin_nickname'];
570     $adminPass = $_POST['admin_password'];
571     $adminPass2 = $_POST['admin_password2'];
572     $adminEmail = $_POST['admin_email'];
573
574     $server = $_SERVER['HTTP_HOST'];
575     $path = substr(dirname($_SERVER['PHP_SELF']), 1);
576
577     echo <<<STR
578     <dl class="system_notice">
579         <dt>Page notice</dt>
580         <dd>
581             <ul>
582 STR;
583     $fail = false;
584
585     if (empty($host)) {
586         updateStatus("No hostname specified.", true);
587         $fail = true;
588     }
589
590     if (empty($database)) {
591         updateStatus("No database specified.", true);
592         $fail = true;
593     }
594
595     if (empty($username)) {
596         updateStatus("No username specified.", true);
597         $fail = true;
598     }
599
600     if (empty($sitename)) {
601         updateStatus("No sitename specified.", true);
602         $fail = true;
603     }
604
605     if (empty($adminNick)) {
606         updateStatus("No initial StatusNet user nickname specified.", true);
607         $fail = true;
608     }
609
610     if (empty($adminPass)) {
611         updateStatus("No initial StatusNet user password specified.", true);
612         $fail = true;
613     }
614     
615     if ($adminPass != $adminPass2) {
616         updateStatus("Administrator passwords do not match. Did you mistype?", true);
617         $fail = true;
618     }
619
620     if ($fail) {
621         showForm();
622         return;
623     }
624
625     global $dbModules;
626     $db = call_user_func($dbModules[$dbtype]['installer'], $host, $database, $username, $password);
627
628     if (!$db) {
629         // database connection failed, do not move on to create config file.
630         return false;
631     }
632
633     updateStatus("Writing config file...");
634     $res = writeConf($sitename, $server, $path, $fancy, $db);
635
636     if (!$res) {
637         updateStatus("Can't write config file.", true);
638         showForm();
639         return;
640     }
641
642     // Okay, cross fingers and try to register an initial user
643     if (registerInitialUser($adminNick, $adminPass, $adminEmail)) {
644         updateStatus(
645             "An initial user with the administrator role has been created."
646         );
647     } else {
648         updateStatus(
649             "Could not create initial StatusNet user (administrator).",
650             true
651         );
652         showForm();
653         return;
654     }
655
656     /*
657         TODO https needs to be considered
658     */
659     $link = "http://".$server.'/'.$path;
660
661     updateStatus("StatusNet has been installed at $link");
662     updateStatus(
663         "You can visit your <a href='$link'>new StatusNet site</a> (login as '$adminNick')."
664     );
665 }
666
667 function Pgsql_Db_installer($host, $database, $username, $password)
668 {
669     $connstring = "dbname=$database host=$host user=$username";
670
671     //No password would mean trust authentication used.
672     if (!empty($password)) {
673         $connstring .= " password=$password";
674     }
675     updateStatus("Starting installation...");
676     updateStatus("Checking database...");
677     $conn = pg_connect($connstring);
678
679     if ($conn ===false) {
680         updateStatus("Failed to connect to database: $connstring");
681         showForm();
682         return false;
683     }
684
685     //ensure database encoding is UTF8
686     $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
687     if ($record->server_encoding != 'UTF8') {
688         updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
689         showForm();
690         return false;
691     }
692
693     updateStatus("Running database script...");
694     //wrap in transaction;
695     pg_query($conn, 'BEGIN');
696     $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
697
698     if ($res === false) {
699         updateStatus("Can't run database script.", true);
700         showForm();
701         return false;
702     }
703     foreach (array('sms_carrier' => 'SMS carrier',
704                 'notice_source' => 'notice source',
705                 'foreign_services' => 'foreign service')
706           as $scr => $name) {
707         updateStatus(sprintf("Adding %s data to database...", $name));
708         $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
709         if ($res === false) {
710             updateStatus(sprintf("Can't run %d script.", $name), true);
711             showForm();
712             return false;
713         }
714     }
715     pg_query($conn, 'COMMIT');
716
717     if (empty($password)) {
718         $sqlUrl = "pgsql://$username@$host/$database";
719     } else {
720         $sqlUrl = "pgsql://$username:$password@$host/$database";
721     }
722
723     $db = array('type' => 'pgsql', 'database' => $sqlUrl);
724
725     return $db;
726 }
727
728 function Mysql_Db_installer($host, $database, $username, $password)
729 {
730     updateStatus("Starting installation...");
731     updateStatus("Checking database...");
732
733     $conn = mysql_connect($host, $username, $password);
734     if (!$conn) {
735         updateStatus("Can't connect to server '$host' as '$username'.", true);
736         showForm();
737         return false;
738     }
739     updateStatus("Changing to database...");
740     $res = mysql_select_db($database, $conn);
741     if (!$res) {
742         updateStatus("Can't change to database.", true);
743         showForm();
744         return false;
745     }
746     updateStatus("Running database script...");
747     $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
748     if ($res === false) {
749         updateStatus("Can't run database script.", true);
750         showForm();
751         return false;
752     }
753     foreach (array('sms_carrier' => 'SMS carrier',
754                 'notice_source' => 'notice source',
755                 'foreign_services' => 'foreign service')
756           as $scr => $name) {
757         updateStatus(sprintf("Adding %s data to database...", $name));
758         $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
759         if ($res === false) {
760             updateStatus(sprintf("Can't run %d script.", $name), true);
761             showForm();
762             return false;
763         }
764     }
765
766     $sqlUrl = "mysqli://$username:$password@$host/$database";
767     $db = array('type' => 'mysql', 'database' => $sqlUrl);
768     return $db;
769 }
770
771 function writeConf($sitename, $server, $path, $fancy, $db)
772 {
773     // assemble configuration file in a string
774     $cfg =  "<?php\n".
775             "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
776
777             // site name
778             "\$config['site']['name'] = '$sitename';\n\n".
779
780             // site location
781             "\$config['site']['server'] = '$server';\n".
782             "\$config['site']['path'] = '$path'; \n\n".
783
784             // checks if fancy URLs are enabled
785             ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
786
787             // database
788             "\$config['db']['database'] = '{$db['database']}';\n\n".
789             ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
790             "\$config['db']['type'] = '{$db['type']}';\n\n";
791     // write configuration file out to install directory
792     $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
793
794     return $res;
795 }
796
797 /**
798  * Install schema into the database
799  *
800  * @param string $filename location of database schema file
801  * @param dbconn $conn     connection to database
802  * @param string $type     type of database, currently mysql or pgsql
803  *
804  * @return boolean - indicating success or failure
805  */
806 function runDbScript($filename, $conn, $type = 'mysqli')
807 {
808     $sql = trim(file_get_contents($filename));
809     $stmts = explode(';', $sql);
810     foreach ($stmts as $stmt) {
811         $stmt = trim($stmt);
812         if (!mb_strlen($stmt)) {
813             continue;
814         }
815         // FIXME: use PEAR::DB or PDO instead of our own switch
816         switch ($type) {
817         case 'mysqli':
818             $res = mysql_query($stmt, $conn);
819             if ($res === false) {
820                 $error = mysql_error();
821             }
822             break;
823         case 'pgsql':
824             $res = pg_query($conn, $stmt);
825             if ($res === false) {
826                 $error = pg_last_error();
827             }
828             break;
829         default:
830             updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
831         }
832         if ($res === false) {
833             updateStatus("ERROR ($error) for SQL '$stmt'");
834             return $res;
835         }
836     }
837     return true;
838 }
839
840 function registerInitialUser($nickname, $password, $email)
841 {
842     define('STATUSNET', true);
843     define('LACONICA', true); // compatibility
844
845     require_once INSTALLDIR . '/lib/common.php';
846
847     $data = array('nickname' => $nickname,
848                   'password' => $password,
849                   'fullname' => $nickname);
850     if ($email) {
851         $data['email'] = $email;
852     }
853     $user = User::register($data);
854
855     if (empty($user)) {
856         return false;
857     }
858
859     // give initial user carte blanche
860
861     $user->grantRole('owner');
862     $user->grantRole('moderator');
863     $user->grantRole('administrator');
864
865     return true;
866 }
867
868 ?>
869 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
870 <!DOCTYPE html
871 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
872        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
873 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
874     <head>
875         <title>Install StatusNet</title>
876         <link rel="shortcut icon" href="favicon.ico"/>
877         <link rel="stylesheet" type="text/css" href="theme/default/css/display.css" media="screen, projection, tv"/>
878         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css" /><![endif]-->
879         <!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css" /><![endif]-->
880         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css" /><![endif]-->
881         <script src="js/jquery.min.js"></script>
882         <script src="js/install.js"></script>
883     </head>
884     <body id="install">
885         <div id="wrap">
886             <div id="header">
887                 <address id="site_contact" class="vcard">
888                     <a class="url home bookmark" href=".">
889                         <img class="logo photo" src="theme/default/logo.png" alt="StatusNet"/>
890                         <span class="fn org">StatusNet</span>
891                     </a>
892                 </address>
893             </div>
894             <div id="core">
895                 <div id="content">
896                      <div id="content_inner">
897                         <h1>Install StatusNet</h1>
898 <?php main(); ?>
899                    </div>
900                 </div>
901             </div>
902         </div>
903     </body>
904 </html>