]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - install.php
fixed up curly brackets and spaces around for, if, else
[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         echo '<li>';
357         if ($library['url']) {
358             echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
359         } else {
360             echo htmlentities($library['name']);
361         }
362         echo '<ul>';
363         if ($library['deb']) {
364             echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
365         }
366         if ($library['rpm']) {
367             echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
368         }
369         if ($library['pear']) {
370             echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
371         }
372         echo '</ul>';
373     }
374     echo<<<E_O_T
375     </ul>
376     <h2>Installed Libraries</h2>
377     <ul id="present_libraries">
378 E_O_T;
379     foreach ($present_libraries as $library) {
380         echo '<li>';
381         if ($library['url']) {
382             echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
383         } else {
384             echo htmlentities($library['name']);
385         }
386         echo '</li>';
387     }
388     echo<<<E_O_T
389     </ul>
390 E_O_T;
391 }
392
393 function showForm()
394 {
395     global $dbModules;
396     $dbRadios = '';
397     $checked = 'checked="checked" '; // Check the first one which exists
398     foreach ($dbModules as $type => $info) {
399         if (checkExtension($info['check_module'])) {
400             $dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
401             $checked = '';
402         }
403     }
404     echo<<<E_O_T
405         </ul>
406     </dd>
407 </dl>
408 <dl id="page_notice" class="system_notice">
409     <dt>Page notice</dt>
410     <dd>
411         <div class="instructions">
412             <p>Enter your database connection information below to initialize the database.</p>
413             <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>
414         </div>
415     </dd>
416 </dl>
417 <form method="post" action="install.php" class="form_settings" id="form_install">
418     <fieldset>
419         <legend>Connection settings</legend>
420         <ul class="form_data">
421             <li>
422                 <label for="sitename">Site name</label>
423                 <input type="text" id="sitename" name="sitename" />
424                 <p class="form_guide">The name of your site</p>
425             </li>
426             <li>
427                 <label for="fancy-enable">Fancy URLs</label>
428                 <input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
429                 <input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
430                 <p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
431             </li>
432             <li>
433                 <label for="host">Hostname</label>
434                 <input type="text" id="host" name="host" />
435                 <p class="form_guide">Database hostname</p>
436             </li>
437             <li>
438
439                 <label for="dbtype">Type</label>
440                 $dbRadios
441                 <p class="form_guide">Database type</p>
442             </li>
443
444             <li>
445                 <label for="database">Name</label>
446                 <input type="text" id="database" name="database" />
447                 <p class="form_guide">Database name</p>
448             </li>
449             <li>
450                 <label for="username">Username</label>
451                 <input type="text" id="username" name="username" />
452                 <p class="form_guide">Database username</p>
453             </li>
454             <li>
455                 <label for="password">Password</label>
456                 <input type="password" id="password" name="password" />
457                 <p class="form_guide">Database password (optional)</p>
458             </li>
459         </ul>
460         <input type="submit" name="submit" class="submit" value="Submit" />
461     </fieldset>
462 </form>
463
464 E_O_T;
465 }
466
467 function updateStatus($status, $error=false)
468 {
469     echo '<li ' . ($error) ? 'class="error"': '';
470     echo ">$status</li>";
471 }
472
473 function handlePost()
474 {
475     $host     = $_POST['host'];
476     $dbtype   = $_POST['dbtype'];
477     $database = $_POST['database'];
478     $username = $_POST['username'];
479     $password = $_POST['password'];
480     $sitename = $_POST['sitename'];
481     $fancy    = !empty($_POST['fancy']);
482     $server = $_SERVER['HTTP_HOST'];
483     $path = substr(dirname($_SERVER['PHP_SELF']), 1);
484
485     echo <<<STR
486     <dl class="system_notice">
487         <dt>Page notice</dt>
488         <dd>
489             <ul>
490 STR;
491     $fail = false;
492
493     if (empty($host)) {
494         updateStatus("No hostname specified.", true);
495         $fail = true;
496     }
497
498     if (empty($database)) {
499         updateStatus("No database specified.", true);
500         $fail = true;
501     }
502
503     if (empty($username)) {
504         updateStatus("No username specified.", true);
505         $fail = true;
506     }
507
508 //     if (empty($password)) {
509 //         updateStatus("No password specified.", true);
510 //              $fail = true;
511 //     }
512
513     if (empty($sitename)) {
514         updateStatus("No sitename specified.", true);
515         $fail = true;
516     }
517
518     if ($fail) {
519         showForm();
520         return;
521     }
522
523     global $dbModules;
524     $db = call_user_func($dbModules[$dbtype]['installer'],
525         $host, $database, $username, $password);
526
527     if (!$db) {
528         // database connection failed, do not move on to create config file.
529         return false;
530     }
531
532     updateStatus("Writing config file...");
533     $res = writeConf($sitename, $server, $path, $fancy, $db);
534
535     if (!$res) {
536         updateStatus("Can't write config file.", true);
537         showForm();
538         return;
539     }
540
541     /*
542         TODO https needs to be considered
543     */
544     $link = "http://".$server.'/'.$path;
545
546     updateStatus("StatusNet has been installed at $link");
547     updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
548 ?>
549
550 <?php
551 }
552
553 function pgsql_db_installer($host, $database, $username, $password) {
554     $connstring = "dbname=$database host=$host user=$username";
555
556     //No password would mean trust authentication used.
557     if (!empty($password)) {
558         $connstring .= " password=$password";
559     }
560     updateStatus("Starting installation...");
561     updateStatus("Checking database...");
562     $conn = pg_connect($connstring);
563
564     if ($conn ===false) {
565         updateStatus("Failed to connect to database: $connstring");
566         showForm();
567         return false;
568     }
569
570     //ensure database encoding is UTF8
571     $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
572     if ($record->server_encoding != 'UTF8') {
573         updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
574         showForm();
575         return false;
576     }
577
578     updateStatus("Running database script...");
579     //wrap in transaction;
580     pg_query($conn, 'BEGIN');
581     $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
582
583     if ($res === false) {
584         updateStatus("Can't run database script.", true);
585         showForm();
586         return false;
587     }
588     foreach (array('sms_carrier' => 'SMS carrier',
589                 'notice_source' => 'notice source',
590                 'foreign_services' => 'foreign service')
591           as $scr => $name) {
592         updateStatus(sprintf("Adding %s data to database...", $name));
593         $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
594         if ($res === false) {
595             updateStatus(sprintf("Can't run %d script.", $name), true);
596             showForm();
597             return false;
598         }
599     }
600     pg_query($conn, 'COMMIT');
601
602     if (empty($password)) {
603         $sqlUrl = "pgsql://$username@$host/$database";
604     } else {
605         $sqlUrl = "pgsql://$username:$password@$host/$database";
606     }
607
608     $db = array('type' => 'pgsql', 'database' => $sqlUrl);
609
610     return $db;
611 }
612
613 function mysql_db_installer($host, $database, $username, $password) {
614     updateStatus("Starting installation...");
615     updateStatus("Checking database...");
616
617     $conn = mysql_connect($host, $username, $password);
618     if (!$conn) {
619         updateStatus("Can't connect to server '$host' as '$username'.", true);
620         showForm();
621         return false;
622     }
623     updateStatus("Changing to database...");
624     $res = mysql_select_db($database, $conn);
625     if (!$res) {
626         updateStatus("Can't change to database.", true);
627         showForm();
628         return false;
629     }
630     updateStatus("Running database script...");
631     $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
632     if ($res === false) {
633         updateStatus("Can't run database script.", true);
634         showForm();
635         return false;
636     }
637     foreach (array('sms_carrier' => 'SMS carrier',
638                 'notice_source' => 'notice source',
639                 'foreign_services' => 'foreign service')
640           as $scr => $name) {
641         updateStatus(sprintf("Adding %s data to database...", $name));
642         $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
643         if ($res === false) {
644             updateStatus(sprintf("Can't run %d script.", $name), true);
645             showForm();
646             return false;
647         }
648     }
649
650     $sqlUrl = "mysqli://$username:$password@$host/$database";
651     $db = array('type' => 'mysql', 'database' => $sqlUrl);
652     return $db;
653 }
654
655 function writeConf($sitename, $server, $path, $fancy, $db)
656 {
657     // assemble configuration file in a string
658     $cfg =  "<?php\n".
659             "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
660
661             // site name
662             "\$config['site']['name'] = '$sitename';\n\n".
663
664             // site location
665             "\$config['site']['server'] = '$server';\n".
666             "\$config['site']['path'] = '$path'; \n\n".
667
668             // checks if fancy URLs are enabled
669             ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
670
671             // database
672             "\$config['db']['database'] = '{$db['database']}';\n\n".
673             ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
674             "\$config['db']['type'] = '{$db['type']}';\n\n".
675
676             "?>";
677     // write configuration file out to install directory
678     $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
679
680     return $res;
681 }
682
683 /**
684  * Install schema into the database
685  *
686  * @param filename $filename    location of database schema file
687  * @param conn $conn            connection to database
688  * @param type $type type of database, currently mysql or pgsql
689  * @return boolean - indicating success or failure
690  */
691 function runDbScript($filename, $conn, $type = 'mysql')
692 {
693     $sql = trim(file_get_contents($filename));
694     $stmts = explode(';', $sql);
695     foreach ($stmts as $stmt) {
696         $stmt = trim($stmt);
697         if (!mb_strlen($stmt)) {
698             continue;
699         }
700         // FIXME: use PEAR::DB or PDO instead of our own switch
701         switch ($type) {
702         case 'mysql':
703             $res = mysql_query($stmt, $conn);
704             if ($res === false) {
705                 $error = mysql_error();
706             }
707             break;
708         case 'pgsql':
709             $res = pg_query($conn, $stmt);
710             if ($res === false) {
711                 $error = pg_last_error();
712             }
713             break;
714         default:
715             updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
716         }
717         if ($res === false) {
718             updateStatus("ERROR ($error) for SQL '$stmt'");
719             return $res;
720         }
721     }
722     return true;
723 }
724
725 ?>
726 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
727 <!DOCTYPE html
728 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
729        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
730 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
731     <head>
732         <title>Install StatusNet</title>
733         <link rel="shortcut icon" href="favicon.ico"/>
734         <link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
735         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
736         <!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
737         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
738         <script src="js/jquery.min.js"></script>
739         <script src="js/install.js"></script>
740     </head>
741     <body id="install">
742         <div id="wrap">
743             <div id="header">
744                 <address id="site_contact" class="vcard">
745                     <a class="url home bookmark" href=".">
746                         <img class="logo photo" src="theme/default/logo.png" alt="StatusNet"/>
747                         <span class="fn org">StatusNet</span>
748                     </a>
749                 </address>
750             </div>
751             <div id="core">
752                 <div id="content">
753                     <h1>Install StatusNet</h1>
754 <?php main(); ?>
755                 </div>
756             </div>
757         </div>
758     </body>
759 </html>