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