3 * StatusNet - the distributed open-source microblogging tool
4 * Copyright (C) 2009, StatusNet, Inc.
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.
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.
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/>.
20 define('INSTALLDIR', dirname(__FILE__));
22 $external_libraries=array(
25 'url'=>'http://us.php.net/manual/en/book.gettext.php',
26 'check_function'=>'gettext'
30 'url'=>'http://pear.php.net/',
32 'include'=>'PEAR.php',
38 'url'=>'http://pear.php.net/package/DB',
40 'include'=>'DB/common.php',
41 'check_class'=>'DB_common'
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'
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'
58 'name'=>'Facebook API',
59 'url'=>'http://developers.facebook.com/',
60 'include'=>'facebook/facebook.php',
61 'check_class'=>'Facebook'
65 'url'=>'http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed',
66 'include'=>'htmLawed/htmLawed.php',
67 'check_function'=>'htmLawed'
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'
80 'url'=>'http://pear.php.net/package/Mail',
82 'include'=>'Mail.php',
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'
96 'url'=>'http://pear.php.net/package/Mime_Type',
97 'include'=>'MIME/Type.php',
98 'check_class'=>'Mime_Type'
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'
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'
118 'url'=>'http://pear.php.net/package/Net_SMTP',
119 'deb'=>'php-net-smtp',
120 'include'=>'Net/SMTP.php',
121 'check_class'=>'Net_SMTP'
126 'url'=>'http://pear.php.net/package/Net_URL',
127 'deb'=>'php-net-url',
128 'include'=>'Net/URL.php',
129 'check_class'=>'Net_URL'
134 'url'=>'http://pear.php.net/package/Net_URL2',
135 'include'=>'Net/URL2.php',
136 'check_class'=>'Net_URL2'
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'
147 'url'=>'http://stomp.codehaus.org/PHP',
148 'include'=>'Stomp.php',
149 'check_class'=>'Stomp'
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'
160 'url'=>'http://code.google.com/p/xmpphp',
161 'include'=>'XMPPHP/XMPP.php',
162 'check_class'=>'XMPPHP_XMPP'
165 'name'=>'PHP Markdown',
166 'url'=>'http://www.michelf.com/projects/php-markdown/',
167 'include'=>'markdown.php',
168 'check_class'=>'Markdown_Parser'
172 'url'=>'http://code.google.com/p/oauth-php',
173 'include'=>'OAuth.php',
174 'check_class'=>'OAuthRequest'
179 'url'=>'http://pear.php.net/package/Validate',
180 'include'=>'Validate.php',
181 'check_class'=>'Validate'
192 if (isset($_GET['checklibs'])) {
195 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
203 function haveExternalLibrary($external_library)
205 if(isset($external_library['include']) && ! haveIncludeFile($external_library['include'])){
208 if(isset($external_library['check_function']) && ! function_exists($external_library['check_function'])){
211 if(isset($external_library['check_class']) && ! class_exists($external_library['check_class'])){
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);
226 function checkPrereqs()
230 if (file_exists(INSTALLDIR.'/config.php')) {
231 ?><p class="error">Config file "config.php" already exists.</p>
236 if (version_compare(PHP_VERSION, '5.2.3', '<')) {
237 ?><p class="error">Require PHP version 5.2.3 or greater.</p><?php
241 $reqs = array('gd', 'curl',
242 'xmlwriter', 'mbstring','tidy');
244 foreach ($reqs as $req) {
245 if (!checkExtension($req)) {
246 ?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php
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
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>
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>
277 function checkExtension($name)
279 if (extension_loaded($name)) {
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;
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;
303 $absent_libraries[]=$external_library;
307 <div class="instructions">
308 <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
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 "aptitude", "apt-get", and "synaptic") 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 "yum", "apt-rpm", and "up2date") 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 "pear install <name>".</p>
314 <h2>Absent Libraries</h2>
315 <ul id="absent_libraries">
317 foreach($absent_libraries as $library)
320 if(isset($library['url'])){
321 echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
323 echo htmlentities($library['name']);
326 if(isset($library['deb'])){
327 echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
329 if(isset($library['rpm'])){
330 echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
332 if(isset($library['pear'])){
333 echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
339 <h2>Installed Libraries</h2>
340 <ul id="present_libraries">
342 foreach($present_libraries as $library)
345 if(isset($library['url'])){
346 echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
348 echo htmlentities($library['name']);
363 <dl id="page_notice" class="system_notice">
366 <div class="instructions">
367 <p>Enter your database connection information below to initialize the database.</p>
368 <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>
372 <form method="post" action="install.php" class="form_settings" id="form_install">
374 <legend>Connection settings</legend>
375 <ul class="form_data">
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>
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>
388 <label for="host">Hostname</label>
389 <input type="text" id="host" name="host" />
390 <p class="form_guide">Database hostname</p>
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>
401 <label for="database">Name</label>
402 <input type="text" id="database" name="database" />
403 <p class="form_guide">Database name</p>
406 <label for="username">Username</label>
407 <input type="text" id="username" name="username" />
408 <p class="form_guide">Database username</p>
411 <label for="password">Password</label>
412 <input type="password" id="password" name="password" />
413 <p class="form_guide">Database password (optional)</p>
416 <input type="submit" name="submit" class="submit" value="Submit" />
423 function updateStatus($status, $error=false)
426 <li <?php echo ($error) ? 'class="error"': ''; ?>><?php echo $status;?></li>
431 function handlePost()
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);
447 <dl class="system_notice">
455 updateStatus("No hostname specified.", true);
459 if (empty($database)) {
460 updateStatus("No database specified.", true);
464 if (empty($username)) {
465 updateStatus("No username specified.", true);
469 // if (empty($password)) {
470 // updateStatus("No password specified.", true);
474 if (empty($sitename)) {
475 updateStatus("No sitename specified.", true);
484 // FIXME: use PEAR::DB or PDO instead of our own switch
488 $db = mysql_db_installer($host, $database, $username, $password);
491 $db = pgsql_db_installer($host, $database, $username, $password);
497 // database connection failed, do not move on to create config file.
501 updateStatus("Writing config file...");
502 $res = writeConf($sitename, $server, $path, $fancy, $db);
505 updateStatus("Can't write config file.", true);
511 TODO https needs to be considered
513 $link = "http://".$server.'/'.$path;
515 updateStatus("StatusNet has been installed at $link");
516 updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
522 function pgsql_db_installer($host, $database, $username, $password) {
523 $connstring = "dbname=$database host=$host user=$username";
525 //No password would mean trust authentication used.
526 if (!empty($password)) {
527 $connstring .= " password=$password";
529 updateStatus("Starting installation...");
530 updateStatus("Checking database...");
531 $conn = pg_connect($connstring);
533 if ($conn ===false) {
534 updateStatus("Failed to connect to database: $connstring");
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));
547 updateStatus("Running database script...");
548 //wrap in transaction;
549 pg_query($conn, 'BEGIN');
550 $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
552 if ($res === false) {
553 updateStatus("Can't run database script.", true);
557 foreach (array('sms_carrier' => 'SMS carrier',
558 'notice_source' => 'notice source',
559 'foreign_services' => 'foreign service')
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);
569 pg_query($conn, 'COMMIT');
571 if (empty($password)) {
572 $sqlUrl = "pgsql://$username@$host/$database";
575 $sqlUrl = "pgsql://$username:$password@$host/$database";
578 $db = array('type' => 'pgsql', 'database' => $sqlUrl);
583 function mysql_db_installer($host, $database, $username, $password) {
584 updateStatus("Starting installation...");
585 updateStatus("Checking database...");
587 $conn = mysql_connect($host, $username, $password);
589 updateStatus("Can't connect to server '$host' as '$username'.", true);
593 updateStatus("Changing to database...");
594 $res = mysql_select_db($database, $conn);
596 updateStatus("Can't change to database.", true);
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);
607 foreach (array('sms_carrier' => 'SMS carrier',
608 'notice_source' => 'notice source',
609 'foreign_services' => 'foreign service')
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);
620 $sqlUrl = "mysqli://$username:$password@$host/$database";
621 $db = array('type' => 'mysql', 'database' => $sqlUrl);
625 function writeConf($sitename, $server, $path, $fancy, $db)
627 // assemble configuration file in a string
629 "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
632 "\$config['site']['name'] = '$sitename';\n\n".
635 "\$config['site']['server'] = '$server';\n".
636 "\$config['site']['path'] = '$path'; \n\n".
638 // checks if fancy URLs are enabled
639 ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
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".
647 // write configuration file out to install directory
648 $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
653 function runDbScript($filename, $conn, $type = 'mysql')
655 $sql = trim(file_get_contents($filename));
656 $stmts = explode(';', $sql);
657 foreach ($stmts as $stmt) {
659 if (!mb_strlen($stmt)) {
662 // FIXME: use PEAR::DB or PDO instead of our own switch
665 $res = mysql_query($stmt, $conn);
666 if ($res === false) {
667 $error = mysql_error();
671 $res = pg_query($conn, $stmt);
672 if ($res === false) {
673 $error = pg_last_error();
677 updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
679 if ($res === false) {
680 updateStatus("ERROR ($error) for SQL '$stmt'");
688 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
690 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
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>
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>
713 <h1>Install StatusNet</h1>