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