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