]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - install.php
Merge branch 'testing' of git@gitorious.org:statusnet/mainline into 0.9.x
[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     // Look for known library bugs
305     $str = "abcdefghijklmnopqrstuvwxyz";
306     $replaced = preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str);
307     if ($str != $replaced) {
308         printf('<p class="error">PHP is linked to a version of the PCRE library ' .
309                'that does not support Unicode properties. ' .
310                'If you are running Red Hat Enterprise Linux / ' .
311                'CentOS 5.4 or earlier, see <a href="' .
312                'http://status.net/wiki/Red_Hat_Enterprise_Linux#PCRE_library' .
313                '">our documentation page</a> on fixing this.</p>');
314         $pass = false;
315     }
316
317     $reqs = array('gd', 'curl',
318                   'xmlwriter', 'mbstring', 'xml', 'dom', 'simplexml');
319
320     foreach ($reqs as $req) {
321         if (!checkExtension($req)) {
322             printf('<p class="error">Cannot load required extension: <code>%s</code></p>', $req);
323             $pass = false;
324         }
325     }
326     // Make sure we have at least one database module available
327     global $dbModules;
328     $missingExtensions = array();
329     foreach ($dbModules as $type => $info) {
330         if (!checkExtension($info['check_module'])) {
331             $missingExtensions[] = $info['check_module'];
332         }
333     }
334
335     if (count($missingExtensions) == count($dbModules)) {
336         $req = implode(', ', $missingExtensions);
337         printf('<p class="error">Cannot find mysql or pgsql extension. You need one or the other.');
338         $pass = false;
339     }
340
341     if (!is_writable(INSTALLDIR)) {
342         printf('<p class="error">Cannot write config file to: <code>%s</code></p>', INSTALLDIR);
343         printf('<p>On your server, try this command: <code>chmod a+w %s</code>', INSTALLDIR);
344         $pass = false;
345     }
346
347     // Check the subdirs used for file uploads
348     $fileSubdirs = array('avatar', 'background', 'file');
349     foreach ($fileSubdirs as $fileSubdir) {
350         $fileFullPath = INSTALLDIR."/$fileSubdir/";
351         if (!is_writable($fileFullPath)) {
352             printf('<p class="error">Cannot write to %s directory: <code>%s</code></p>', $fileSubdir, $fileFullPath);
353             printf('<p>On your server, try this command: <code>chmod a+w %s</code></p>', $fileFullPath);
354             $pass = false;
355         }
356     }
357
358     return $pass;
359 }
360
361 /**
362  * Checks if a php extension is both installed and loaded
363  *
364  * @param string $name of extension to check
365  *
366  * @return boolean whether extension is installed and loaded
367  */
368 function checkExtension($name)
369 {
370     if (extension_loaded($name)) {
371         return true;
372     } elseif (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode')) {
373         // dl will throw a fatal error if it's disabled or we're in safe mode.
374         // More fun, it may not even exist under some SAPIs in 5.3.0 or later...
375         $soname = $name . '.' . PHP_SHLIB_SUFFIX;
376         if (PHP_SHLIB_SUFFIX == 'dll') {
377             $soname = "php_" . $soname;
378         }
379         return @dl($soname);
380     } else {
381         return false;
382     }
383 }
384
385 /**
386  * Show list of libraries
387  *
388  * @return void
389  */
390 function showLibs()
391 {
392     global $external_libraries;
393     $present_libraries=array();
394     $absent_libraries=array();
395     foreach ($external_libraries as $external_library) {
396         if (haveExternalLibrary($external_library)) {
397             $present_libraries[]=$external_library;
398         } else {
399             $absent_libraries[]=$external_library;
400         }
401     }
402     echo<<<E_O_T
403     <div class="instructions">
404         <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
405         libraries instead, as they tend to provide security updates faster, and may offer improved performance.</p>
406         <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>
407         <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>
408         <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>
409     </div>
410     <h2>Absent Libraries</h2>
411     <ul id="absent_libraries">
412 E_O_T;
413     foreach ($absent_libraries as $library) {
414         echo '<li>';
415         if (isset($library['url'])) {
416             echo '<a href="'.$library['url'].'">'.htmlentities($library['name']).'</a>';
417         } else {
418             echo htmlentities($library['name']);
419         }
420         echo '<ul>';
421         if (isset($library['deb'])) {
422             echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
423         }
424         if (isset($library['rpm'])) {
425             echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
426         }
427         if (isset($library['pear'])) {
428             echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
429         }
430         echo '</ul>';
431     }
432     echo<<<E_O_T
433     </ul>
434     <h2>Installed Libraries</h2>
435     <ul id="present_libraries">
436 E_O_T;
437     foreach ($present_libraries as $library) {
438         echo '<li>';
439         if (isset($library['url'])) {
440             echo '<a href="'.$library['url'].'">'.htmlentities($library['name']).'</a>';
441         } else {
442             echo htmlentities($library['name']);
443         }
444         echo '</li>';
445     }
446     echo<<<E_O_T
447     </ul>
448 E_O_T;
449 }
450
451 /**
452  * Helper class for building form
453  */
454 class Posted {
455     function value($name)
456     {
457         if (isset($_POST[$name])) {
458             return htmlspecialchars(strval($_POST[$name]));
459         } else {
460             return '';
461         }
462     }
463 }
464
465 function showForm()
466 {
467     global $dbModules;
468     $post = new Posted();
469     $dbRadios = '';
470     if (isset($_POST['dbtype'])) {
471         $dbtype = $_POST['dbtype'];
472     } else {
473         $dbtype = null;
474     }
475     foreach ($dbModules as $type => $info) {
476         if (checkExtension($info['check_module'])) {
477             if ($dbtype == null || $dbtype == $type) {
478                 $checked = 'checked="checked" ';
479                 $dbtype = $type; // if we didn't have one checked, hit the first
480             } else {
481                 $checked = '';
482             }
483             $dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
484         }
485     }
486
487     echo<<<E_O_T
488         </ul>
489     </dd>
490 </dl>
491 <form method="post" action="install.php" class="form_settings" id="form_install">
492     <fieldset>
493         <fieldset id="settings_site">
494             <legend>Site settings</legend>
495             <ul class="form_data">
496                 <li>
497                     <label for="sitename">Site name</label>
498                     <input type="text" id="sitename" name="sitename" value="{$post->value('sitename')}" />
499                     <p class="form_guide">The name of your site</p>
500                 </li>
501                 <li>
502                     <label for="fancy-enable">Fancy URLs</label>
503                     <input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
504                     <input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
505                     <p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
506                 </li>
507             </ul>
508         </fieldset>
509
510         <fieldset id="settings_db">
511             <legend>Database settings</legend>
512             <ul class="form_data">
513                 <li>
514                     <label for="host">Hostname</label>
515                     <input type="text" id="host" name="host" value="{$post->value('host')}" />
516                     <p class="form_guide">Database hostname</p>
517                 </li>
518                 <li>
519                     <label for="dbtype">Type</label>
520                     $dbRadios
521                     <p class="form_guide">Database type</p>
522                 </li>
523                 <li>
524                     <label for="database">Name</label>
525                     <input type="text" id="database" name="database" value="{$post->value('database')}" />
526                     <p class="form_guide">Database name</p>
527                 </li>
528                 <li>
529                     <label for="dbusername">DB username</label>
530                     <input type="text" id="dbusername" name="dbusername" value="{$post->value('dbusername')}" />
531                     <p class="form_guide">Database username</p>
532                 </li>
533                 <li>
534                     <label for="dbpassword">DB password</label>
535                     <input type="password" id="dbpassword" name="dbpassword" value="{$post->value('dbpassword')}" />
536                     <p class="form_guide">Database password (optional)</p>
537                 </li>
538             </ul>
539         </fieldset>
540
541         <fieldset id="settings_admin">
542             <legend>Administrator settings</legend>
543             <ul class="form_data">
544                 <li>
545                     <label for="admin_nickname">Administrator nickname</label>
546                     <input type="text" id="admin_nickname" name="admin_nickname" value="{$post->value('admin_nickname')}" />
547                     <p class="form_guide">Nickname for the initial StatusNet user (administrator)</p>
548                 </li>
549                 <li>
550                     <label for="admin_password">Administrator password</label>
551                     <input type="password" id="admin_password" name="admin_password" value="{$post->value('admin_password')}" />
552                     <p class="form_guide">Password for the initial StatusNet user (administrator)</p>
553                 </li>
554                 <li>
555                     <label for="admin_password2">Confirm password</label>
556                     <input type="password" id="admin_password2" name="admin_password2" value="{$post->value('admin_password2')}" />
557                 </li>
558                 <li>
559                     <label for="admin_email">Administrator e-mail</label>
560                     <input id="admin_email" name="admin_email" value="{$post->value('admin_email')}" />
561                     <p class="form_guide">Optional email address for the initial StatusNet user (administrator)</p>
562                 </li>
563                 <li>
564                     <label for="admin_updates">Subscribe to announcements</label>
565                     <input type="checkbox" id="admin_updates" name="admin_updates" value="true" checked="checked" />
566                     <p class="form_guide">Release and security feed from <a href="http://update.status.net/">update@status.net</a> (recommended)</p>
567                 </li>
568             </ul>
569         </fieldset>
570         <input type="submit" name="submit" class="submit" value="Submit" />
571     </fieldset>
572 </form>
573
574 E_O_T;
575 }
576
577 function updateStatus($status, $error=false)
578 {
579     echo '<li' . ($error ? ' class="error"': '' ) . ">$status</li>";
580 }
581
582 function handlePost()
583 {
584     $host     = $_POST['host'];
585     $dbtype   = $_POST['dbtype'];
586     $database = $_POST['database'];
587     $username = $_POST['dbusername'];
588     $password = $_POST['dbpassword'];
589     $sitename = $_POST['sitename'];
590     $fancy    = !empty($_POST['fancy']);
591
592     $adminNick = $_POST['admin_nickname'];
593     $adminPass = $_POST['admin_password'];
594     $adminPass2 = $_POST['admin_password2'];
595     $adminEmail = $_POST['admin_email'];
596     $adminUpdates = $_POST['admin_updates'];
597
598     $server = $_SERVER['HTTP_HOST'];
599     $path = substr(dirname($_SERVER['PHP_SELF']), 1);
600
601     echo <<<STR
602     <dl class="system_notice">
603         <dt>Page notice</dt>
604         <dd>
605             <ul>
606 STR;
607     $fail = false;
608
609     if (empty($host)) {
610         updateStatus("No hostname specified.", true);
611         $fail = true;
612     }
613
614     if (empty($database)) {
615         updateStatus("No database specified.", true);
616         $fail = true;
617     }
618
619     if (empty($username)) {
620         updateStatus("No username specified.", true);
621         $fail = true;
622     }
623
624     if (empty($sitename)) {
625         updateStatus("No sitename specified.", true);
626         $fail = true;
627     }
628
629     if (empty($adminNick)) {
630         updateStatus("No initial StatusNet user nickname specified.", true);
631         $fail = true;
632     }
633
634     if (empty($adminPass)) {
635         updateStatus("No initial StatusNet user password specified.", true);
636         $fail = true;
637     }
638     
639     if ($adminPass != $adminPass2) {
640         updateStatus("Administrator passwords do not match. Did you mistype?", true);
641         $fail = true;
642     }
643
644     if ($fail) {
645         showForm();
646         return;
647     }
648
649     global $dbModules;
650     $db = call_user_func($dbModules[$dbtype]['installer'], $host, $database, $username, $password);
651
652     if (!$db) {
653         // database connection failed, do not move on to create config file.
654         return false;
655     }
656
657     updateStatus("Writing config file...");
658     $res = writeConf($sitename, $server, $path, $fancy, $db);
659
660     if (!$res) {
661         updateStatus("Can't write config file.", true);
662         showForm();
663         return;
664     }
665
666     // Okay, cross fingers and try to register an initial user
667     if (registerInitialUser($adminNick, $adminPass, $adminEmail, $adminUpdates)) {
668         updateStatus(
669             "An initial user with the administrator role has been created."
670         );
671     } else {
672         updateStatus(
673             "Could not create initial StatusNet user (administrator).",
674             true
675         );
676         showForm();
677         return;
678     }
679
680     /*
681         TODO https needs to be considered
682     */
683     $link = "http://".$server.'/'.$path;
684
685     updateStatus("StatusNet has been installed at $link");
686     updateStatus(
687         "<strong>DONE!</strong> You can visit your <a href='$link'>new StatusNet site</a> (login as '$adminNick'). If this is your first StatusNet install, you may want to poke around our <a href='http://status.net/wiki/Getting_started'>Getting Started guide</a>."
688     );
689 }
690
691 function Pgsql_Db_installer($host, $database, $username, $password)
692 {
693     $connstring = "dbname=$database host=$host user=$username";
694
695     //No password would mean trust authentication used.
696     if (!empty($password)) {
697         $connstring .= " password=$password";
698     }
699     updateStatus("Starting installation...");
700     updateStatus("Checking database...");
701     $conn = pg_connect($connstring);
702
703     if ($conn ===false) {
704         updateStatus("Failed to connect to database: $connstring");
705         showForm();
706         return false;
707     }
708
709     //ensure database encoding is UTF8
710     $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
711     if ($record->server_encoding != 'UTF8') {
712         updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
713         showForm();
714         return false;
715     }
716
717     updateStatus("Running database script...");
718     //wrap in transaction;
719     pg_query($conn, 'BEGIN');
720     $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
721
722     if ($res === false) {
723         updateStatus("Can't run database script.", true);
724         showForm();
725         return false;
726     }
727     foreach (array('sms_carrier' => 'SMS carrier',
728                 'notice_source' => 'notice source',
729                 'foreign_services' => 'foreign service')
730           as $scr => $name) {
731         updateStatus(sprintf("Adding %s data to database...", $name));
732         $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
733         if ($res === false) {
734             updateStatus(sprintf("Can't run %d script.", $name), true);
735             showForm();
736             return false;
737         }
738     }
739     pg_query($conn, 'COMMIT');
740
741     if (empty($password)) {
742         $sqlUrl = "pgsql://$username@$host/$database";
743     } else {
744         $sqlUrl = "pgsql://$username:$password@$host/$database";
745     }
746
747     $db = array('type' => 'pgsql', 'database' => $sqlUrl);
748
749     return $db;
750 }
751
752 function Mysql_Db_installer($host, $database, $username, $password)
753 {
754     updateStatus("Starting installation...");
755     updateStatus("Checking database...");
756
757     $conn = mysql_connect($host, $username, $password);
758     if (!$conn) {
759         updateStatus("Can't connect to server '$host' as '$username'.", true);
760         showForm();
761         return false;
762     }
763     updateStatus("Changing to database...");
764     $res = mysql_select_db($database, $conn);
765     if (!$res) {
766         updateStatus("Can't change to database.", true);
767         showForm();
768         return false;
769     }
770     updateStatus("Running database script...");
771     $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
772     if ($res === false) {
773         updateStatus("Can't run database script.", true);
774         showForm();
775         return false;
776     }
777     foreach (array('sms_carrier' => 'SMS carrier',
778                 'notice_source' => 'notice source',
779                 'foreign_services' => 'foreign service')
780           as $scr => $name) {
781         updateStatus(sprintf("Adding %s data to database...", $name));
782         $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
783         if ($res === false) {
784             updateStatus(sprintf("Can't run %d script.", $name), true);
785             showForm();
786             return false;
787         }
788     }
789
790     $sqlUrl = "mysqli://$username:$password@$host/$database";
791     $db = array('type' => 'mysql', 'database' => $sqlUrl);
792     return $db;
793 }
794
795 function writeConf($sitename, $server, $path, $fancy, $db)
796 {
797     // assemble configuration file in a string
798     $cfg =  "<?php\n".
799             "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
800
801             // site name
802             "\$config['site']['name'] = '$sitename';\n\n".
803
804             // site location
805             "\$config['site']['server'] = '$server';\n".
806             "\$config['site']['path'] = '$path'; \n\n".
807
808             // checks if fancy URLs are enabled
809             ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
810
811             // database
812             "\$config['db']['database'] = '{$db['database']}';\n\n".
813             ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
814             "\$config['db']['type'] = '{$db['type']}';\n\n";
815     // write configuration file out to install directory
816     $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
817
818     return $res;
819 }
820
821 /**
822  * Install schema into the database
823  *
824  * @param string $filename location of database schema file
825  * @param dbconn $conn     connection to database
826  * @param string $type     type of database, currently mysql or pgsql
827  *
828  * @return boolean - indicating success or failure
829  */
830 function runDbScript($filename, $conn, $type = 'mysqli')
831 {
832     $sql = trim(file_get_contents($filename));
833     $stmts = explode(';', $sql);
834     foreach ($stmts as $stmt) {
835         $stmt = trim($stmt);
836         if (!mb_strlen($stmt)) {
837             continue;
838         }
839         // FIXME: use PEAR::DB or PDO instead of our own switch
840         switch ($type) {
841         case 'mysqli':
842             $res = mysql_query($stmt, $conn);
843             if ($res === false) {
844                 $error = mysql_error();
845             }
846             break;
847         case 'pgsql':
848             $res = pg_query($conn, $stmt);
849             if ($res === false) {
850                 $error = pg_last_error();
851             }
852             break;
853         default:
854             updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
855         }
856         if ($res === false) {
857             updateStatus("ERROR ($error) for SQL '$stmt'");
858             return $res;
859         }
860     }
861     return true;
862 }
863
864 function registerInitialUser($nickname, $password, $email, $adminUpdates)
865 {
866     define('STATUSNET', true);
867     define('LACONICA', true); // compatibility
868
869     require_once INSTALLDIR . '/lib/common.php';
870
871     $data = array('nickname' => $nickname,
872                   'password' => $password,
873                   'fullname' => $nickname);
874     if ($email) {
875         $data['email'] = $email;
876     }
877     $user = User::register($data);
878
879     if (empty($user)) {
880         return false;
881     }
882
883     // give initial user carte blanche
884
885     $user->grantRole('owner');
886     $user->grantRole('moderator');
887     $user->grantRole('administrator');
888     
889     // Attempt to do a remote subscribe to update@status.net
890     // Will fail if instance is on a private network.
891
892     if (class_exists('Ostatus_profile') && $adminUpdates) {
893         try {
894             $oprofile = Ostatus_profile::ensureProfile('http://update.status.net/');
895             Subscription::start($user->getProfile(), $oprofile->localProfile());
896             updateStatus("Set up subscription to <a href='http://update.status.net/'>update@status.net</a>.");
897         } catch (Exception $e) {
898             updateStatus("Could not set up subscription to <a href='http://update.status.net/'>update@status.net</a>.");
899         }
900     }
901
902     return true;
903 }
904
905 ?>
906 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
907 <!DOCTYPE html
908 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
909        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
910 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
911     <head>
912         <title>Install StatusNet</title>
913         <link rel="shortcut icon" href="favicon.ico"/>
914         <link rel="stylesheet" type="text/css" href="theme/default/css/display.css" media="screen, projection, tv"/>
915         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css" /><![endif]-->
916         <!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css" /><![endif]-->
917         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css" /><![endif]-->
918         <script src="js/jquery.min.js"></script>
919         <script src="js/install.js"></script>
920     </head>
921     <body id="install">
922         <div id="wrap">
923             <div id="header">
924                 <address id="site_contact" class="vcard">
925                     <a class="url home bookmark" href=".">
926                         <img class="logo photo" src="theme/default/logo.png" alt="StatusNet"/>
927                         <span class="fn org">StatusNet</span>
928                     </a>
929                 </address>
930             </div>
931             <div id="core">
932                 <div id="content">
933                      <div id="content_inner">
934                         <h1>Install StatusNet</h1>
935 <?php main(); ?>
936                    </div>
937                 </div>
938             </div>
939         </div>
940     </body>
941 </html>