]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - install.php
64c8fd9b14f6a0540499f19286bd65c5127552dc
[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 function haveExternalLibrary($external_library)
228 {
229     if (isset($external_library['include']) && ! include_once $external_library['include'] ) {
230         return false;
231     }
232     if (isset($external_library['check_function']) && ! function_exists($external_library['check_function'])) {
233         return false;
234     }
235     if (isset($external_library['check_class']) && ! class_exists($external_library['check_class'])) {
236         return false;
237     }
238     return true;
239 }
240
241 function checkPrereqs()
242 {
243     $pass = true;
244
245     if (file_exists(INSTALLDIR.'/config.php')) {
246          printf('<p class="error">Config file &quot;config.php&quot; already exists.</p>');
247         $pass = false;
248     }
249
250     if (version_compare(PHP_VERSION, '5.2.3', '<')) {
251         printf('<p class="error">Require PHP version 5.2.3 or greater.</p>');
252         $pass = false;
253     }
254
255     $reqs = array('gd', 'curl',
256                   'xmlwriter', 'mbstring','tidy');
257
258     foreach ($reqs as $req) {
259         if (!checkExtension($req)) {
260             printf('<p class="error">Cannot load required extension: <code>%s</code></p>', $req);
261             $pass = false;
262         }
263     }    
264     // Make sure we have at least one database module available
265     global $dbModules;
266     $missingExtensions = array();
267     foreach ($dbModules as $type => $info) {
268         if (!checkExtension($info['check_module'])) {
269             $missingExtensions[] = $info['check_module'];
270         }
271     }
272     if (count($missingExtensions) == count($dbModules)) {
273         $req = implode(', ', $missingExtensions);
274         printf('<p class="error">Cannot find mysql or pgsql extension. You need one or the other: <code>%s</code></p>', $req);
275         $pass = false;
276     }
277     
278     if (!is_writable(INSTALLDIR)) {
279         printf('<p class="error">Cannot write config file to: <code>%s</code></p>', INSTALLDIR);
280         printf('<p>On your server, try this command: <code>chmod a+w %s</code>', INSTALLDIR);
281         $pass = false;
282     }
283
284     // Check the subdirs used for file uploads
285     $fileSubdirs = array('avatar', 'background', 'file');
286     foreach ($fileSubdirs as $fileSubdir) {
287         $fileFullPath = INSTALLDIR."/$fileSubdir/";
288         if (!is_writable($fileFullPath)) {
289             printf('<p class="error">Cannot write to %s directory: <code>%s</code></p>', $fileSubdir, $fileFullPath);
290             printf('<p>On your server, try this command: <code>chmod a+w %s</code></p>', $fileFullPath);
291             $pass = false;
292         }
293     }
294
295     return $pass;
296 }
297
298 function checkExtension($name)
299 {
300     if (!extension_loaded($name)) {
301         if (!@dl($name.'.so')) {
302             return false;
303         }
304     }
305     return true;
306 }
307
308 function showLibs()
309 {
310     global $external_libraries;
311     $present_libraries=array();
312     $absent_libraries=array();
313     foreach ($external_libraries as $external_library){
314         if (haveExternalLibrary($external_library)) {
315             $present_libraries[]=$external_library;
316         } else {
317             $absent_libraries[]=$external_library;
318         }
319     }
320     echo<<<E_O_T
321     <div class="instructions">
322         <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
323         libraries instead, as they tend to provide security updates faster, and may offer improved performance.</p>
324         <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>
325         <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>
326         <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>
327     </div>
328     <h2>Absent Libraries</h2>
329     <ul id="absent_libraries">
330 E_O_T;
331     foreach($absent_libraries as $library)
332     {
333         echo '<li>';
334         if($library['url']){
335             echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
336         }else{
337             echo htmlentities($library['name']);
338         }
339         echo '<ul>';
340         if($library['deb']){
341             echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
342         }
343         if($library['rpm']){
344             echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
345         }
346         if($library['pear']){
347             echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
348         }
349         echo '</ul>';
350     }
351     echo<<<E_O_T
352     </ul>
353     <h2>Installed Libraries</h2>
354     <ul id="present_libraries">
355 E_O_T;
356     foreach($present_libraries as $library)
357     {
358         echo '<li>';
359         if($library['url']){
360             echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
361         }else{
362             echo htmlentities($library['name']);
363         }
364         echo '</li>';
365     }
366     echo<<<E_O_T
367     </ul>
368 E_O_T;
369 }
370
371 function showForm()
372 {
373     global $dbModules;
374     $dbRadios = '';
375     $checked = 'checked="checked" '; // Check the first one which exists
376     foreach ($dbModules as $type => $info) {
377         if (checkExtension($info['check_module'])) {
378             $dbRadios .= "<input type=\"radio\" name=\"dbtype\" id=\"dbtype-$type\" value=\"$type\" $checked/> $info[name]<br />\n";
379             $checked = '';
380         }
381     }
382     echo<<<E_O_T
383         </ul>
384     </dd>
385 </dl>
386 <dl id="page_notice" class="system_notice">
387     <dt>Page notice</dt>
388     <dd>
389         <div class="instructions">
390             <p>Enter your database connection information below to initialize the database.</p>
391             <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>
392         </div>
393     </dd>
394 </dl>
395 <form method="post" action="install.php" class="form_settings" id="form_install">
396     <fieldset>
397         <legend>Connection settings</legend>
398         <ul class="form_data">
399             <li>
400                 <label for="sitename">Site name</label>
401                 <input type="text" id="sitename" name="sitename" />
402                 <p class="form_guide">The name of your site</p>
403             </li>
404             <li>
405                 <label for="fancy-enable">Fancy URLs</label>
406                 <input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
407                 <input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
408                 <p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
409             </li>
410             <li>
411                 <label for="host">Hostname</label>
412                 <input type="text" id="host" name="host" />
413                 <p class="form_guide">Database hostname</p>
414             </li>
415             <li>
416
417                 <label for="dbtype">Type</label>
418                 $dbRadios
419                 <p class="form_guide">Database type</p>
420             </li>
421
422             <li>
423                 <label for="database">Name</label>
424                 <input type="text" id="database" name="database" />
425                 <p class="form_guide">Database name</p>
426             </li>
427             <li>
428                 <label for="username">Username</label>
429                 <input type="text" id="username" name="username" />
430                 <p class="form_guide">Database username</p>
431             </li>
432             <li>
433                 <label for="password">Password</label>
434                 <input type="password" id="password" name="password" />
435                 <p class="form_guide">Database password (optional)</p>
436             </li>
437         </ul>
438         <input type="submit" name="submit" class="submit" value="Submit" />
439     </fieldset>
440 </form>
441
442 E_O_T;
443 }
444
445 function updateStatus($status, $error=false)
446 {
447     echo '<li ' . ($error) ? 'class="error"': '';
448     echo ">$status</li>";
449 }
450
451 function handlePost()
452 {
453 ?>
454
455 <?php
456     $host     = $_POST['host'];
457     $dbtype   = $_POST['dbtype'];
458     $database = $_POST['database'];
459     $username = $_POST['username'];
460     $password = $_POST['password'];
461     $sitename = $_POST['sitename'];
462     $fancy    = !empty($_POST['fancy']);
463     $server = $_SERVER['HTTP_HOST'];
464     $path = substr(dirname($_SERVER['PHP_SELF']), 1);
465
466 ?>
467     <dl class="system_notice">
468         <dt>Page notice</dt>
469         <dd>
470             <ul>
471 <?php
472         $fail = false;
473
474     if (empty($host)) {
475         updateStatus("No hostname specified.", true);
476                 $fail = true;
477     }
478
479     if (empty($database)) {
480         updateStatus("No database specified.", true);
481                 $fail = true;
482     }
483
484     if (empty($username)) {
485         updateStatus("No username specified.", true);
486                 $fail = true;
487     }
488
489 //     if (empty($password)) {
490 //         updateStatus("No password specified.", true);
491 //              $fail = true;
492 //     }
493
494     if (empty($sitename)) {
495         updateStatus("No sitename specified.", true);
496                 $fail = true;
497     }
498
499     if($fail){
500             showForm();
501         return;
502     }
503
504     global $dbModules;
505     $db = call_user_func($dbModules[$dbtype]['installer'],
506         $host, $database, $username, $password);
507
508     if (!$db) {
509         // database connection failed, do not move on to create config file.
510         return false;
511     }
512
513     updateStatus("Writing config file...");
514     $res = writeConf($sitename, $server, $path, $fancy, $db);
515
516     if (!$res) {
517         updateStatus("Can't write config file.", true);
518         showForm();
519         return;
520     }
521
522     /*
523         TODO https needs to be considered
524     */
525     $link = "http://".$server.'/'.$path;
526
527     updateStatus("StatusNet has been installed at $link");
528     updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
529 ?>
530
531 <?php
532 }
533
534 function pgsql_db_installer($host, $database, $username, $password) {
535   $connstring = "dbname=$database host=$host user=$username";
536
537   //No password would mean trust authentication used.
538   if (!empty($password)) {
539     $connstring .= " password=$password";
540   }
541   updateStatus("Starting installation...");
542   updateStatus("Checking database...");
543   $conn = pg_connect($connstring);
544
545   if ($conn ===false) {
546     updateStatus("Failed to connect to database: $connstring");
547     showForm();
548     return false;
549   }
550
551   //ensure database encoding is UTF8
552   $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
553   if ($record->server_encoding != 'UTF8') {
554     updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
555     showForm();
556     return false;
557   }
558
559   updateStatus("Running database script...");
560   //wrap in transaction;
561   pg_query($conn, 'BEGIN');
562   $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
563
564   if ($res === false) {
565       updateStatus("Can't run database script.", true);
566       showForm();
567       return false;
568   }
569   foreach (array('sms_carrier' => 'SMS carrier',
570                 'notice_source' => 'notice source',
571                 'foreign_services' => 'foreign service')
572           as $scr => $name) {
573       updateStatus(sprintf("Adding %s data to database...", $name));
574       $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
575       if ($res === false) {
576           updateStatus(sprintf("Can't run %d script.", $name), true);
577           showForm();
578           return false;
579       }
580   }
581   pg_query($conn, 'COMMIT');
582
583   if (empty($password)) {
584     $sqlUrl = "pgsql://$username@$host/$database";
585   }
586   else {
587     $sqlUrl = "pgsql://$username:$password@$host/$database";
588   }
589
590   $db = array('type' => 'pgsql', 'database' => $sqlUrl);
591
592   return $db;
593 }
594
595 function mysql_db_installer($host, $database, $username, $password) {
596   updateStatus("Starting installation...");
597   updateStatus("Checking database...");
598
599   $conn = mysql_connect($host, $username, $password);
600   if (!$conn) {
601       updateStatus("Can't connect to server '$host' as '$username'.", true);
602       showForm();
603       return false;
604   }
605   updateStatus("Changing to database...");
606   $res = mysql_select_db($database, $conn);
607   if (!$res) {
608       updateStatus("Can't change to database.", true);
609       showForm();
610       return false;
611   }
612   updateStatus("Running database script...");
613   $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
614   if ($res === false) {
615       updateStatus("Can't run database script.", true);
616       showForm();
617       return false;
618   }
619   foreach (array('sms_carrier' => 'SMS carrier',
620                 'notice_source' => 'notice source',
621                 'foreign_services' => 'foreign service')
622           as $scr => $name) {
623       updateStatus(sprintf("Adding %s data to database...", $name));
624       $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
625       if ($res === false) {
626           updateStatus(sprintf("Can't run %d script.", $name), true);
627           showForm();
628           return false;
629       }
630   }
631
632       $sqlUrl = "mysqli://$username:$password@$host/$database";
633       $db = array('type' => 'mysql', 'database' => $sqlUrl);
634       return $db;
635 }
636
637 function writeConf($sitename, $server, $path, $fancy, $db)
638 {
639     // assemble configuration file in a string
640     $cfg =  "<?php\n".
641             "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
642
643             // site name
644             "\$config['site']['name'] = '$sitename';\n\n".
645
646             // site location
647             "\$config['site']['server'] = '$server';\n".
648             "\$config['site']['path'] = '$path'; \n\n".
649
650             // checks if fancy URLs are enabled
651             ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
652
653             // database
654             "\$config['db']['database'] = '{$db['database']}';\n\n".
655             ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
656             "\$config['db']['type'] = '{$db['type']}';\n\n".
657
658             "?>";
659     // write configuration file out to install directory
660     $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
661
662     return $res;
663 }
664
665 function runDbScript($filename, $conn, $type = 'mysql')
666 {
667     $sql = trim(file_get_contents($filename));
668     $stmts = explode(';', $sql);
669     foreach ($stmts as $stmt) {
670         $stmt = trim($stmt);
671         if (!mb_strlen($stmt)) {
672             continue;
673         }
674         // FIXME: use PEAR::DB or PDO instead of our own switch
675         switch ($type) {
676         case 'mysql':
677             $res = mysql_query($stmt, $conn);
678             if ($res === false) {
679                 $error = mysql_error();
680             }
681             break;
682         case 'pgsql':
683             $res = pg_query($conn, $stmt);
684             if ($res === false) {
685                 $error = pg_last_error();
686             }
687             break;
688         default:
689             updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
690         }
691         if ($res === false) {
692             updateStatus("ERROR ($error) for SQL '$stmt'");
693             return $res;
694         }
695     }
696     return true;
697 }
698
699 ?>
700 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
701 <!DOCTYPE html
702 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
703        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
704 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
705     <head>
706         <title>Install StatusNet</title>
707         <link rel="shortcut icon" href="favicon.ico"/>
708         <link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
709         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
710         <!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
711         <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
712         <script src="js/jquery.min.js"></script>
713         <script src="js/install.js"></script>
714     </head>
715     <body id="install">
716         <div id="wrap">
717             <div id="header">
718                 <address id="site_contact" class="vcard">
719                     <a class="url home bookmark" href=".">
720                         <img class="logo photo" src="theme/default/logo.png" alt="StatusNet"/>
721                         <span class="fn org">StatusNet</span>
722                     </a>
723                 </address>
724             </div>
725             <div id="core">
726                 <div id="content">
727                     <h1>Install StatusNet</h1>
728 <?php main(); ?>
729                 </div>
730             </div>
731         </div>
732     </body>
733 </html>