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( $_GET['checklibs'] ){
195 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
203 function haveExternalLibrary($external_library)
205 if(isset($external_library['include']) && ! include_once($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 function checkPrereqs()
221 if (file_exists(INSTALLDIR.'/config.php')) {
222 ?><p class="error">Config file "config.php" already exists.</p>
227 if (version_compare(PHP_VERSION, '5.2.3', '<')) {
228 ?><p class="error">Require PHP version 5.2.3 or greater.</p><?php
232 $reqs = array('gd', 'curl',
233 'xmlwriter', 'mbstring','tidy');
235 foreach ($reqs as $req) {
236 if (!checkExtension($req)) {
237 ?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php
241 if (!checkExtension('pgsql') && !checkExtension('mysql')) {
242 ?><p class="error">Cannot find mysql or pgsql extension. You need one or the other: <code><?php echo $req; ?></code></p><?php
246 if (!is_writable(INSTALLDIR)) {
247 ?><p class="error">Cannot write config file to: <code><?php echo INSTALLDIR; ?></code></p>
248 <p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?></code>
253 // Check the subdirs used for file uploads
254 $fileSubdirs = array('avatar', 'background', 'file');
255 foreach ($fileSubdirs as $fileSubdir) {
256 $fileFullPath = INSTALLDIR."/$fileSubdir/";
257 if (!is_writable($fileFullPath)) {
258 ?><p class="error">Cannot write <?php echo $fileSubdir; ?> directory: <code><?php echo $fileFullPath; ?></code></p>
259 <p>On your server, try this command: <code>chmod a+w <?php echo $fileFullPath; ?></code></p>
268 function checkExtension($name)
270 if (extension_loaded($name)) {
272 } elseif (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode')) {
273 // dl will throw a fatal error if it's disabled or we're in safe mode.
274 // More fun, it may not even exist under some SAPIs in 5.3.0 or later...
275 $soname = $name . '.' . PHP_SHLIB_SUFFIX;
276 if (PHP_SHLIB_SUFFIX == 'dll') {
277 $soname = "php_" . $soname;
287 global $external_libraries;
288 $present_libraries=array();
289 $absent_libraries=array();
290 foreach($external_libraries as $external_library){
291 if(haveExternalLibrary($external_library)){
292 $present_libraries[]=$external_library;
294 $absent_libraries[]=$external_library;
298 <div class="instructions">
299 <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
300 libraries instead, as they tend to provide security updates faster, and may offer improved performance.</p>
301 <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>
302 <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>
303 <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>
305 <h2>Absent Libraries</h2>
306 <ul id="absent_libraries">
308 foreach($absent_libraries as $library)
312 echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
314 echo htmlentities($library['name']);
318 echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
321 echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
323 if($library['pear']){
324 echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
330 <h2>Installed Libraries</h2>
331 <ul id="present_libraries">
333 foreach($present_libraries as $library)
337 echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
339 echo htmlentities($library['name']);
354 <dl id="page_notice" class="system_notice">
357 <div class="instructions">
358 <p>Enter your database connection information below to initialize the database.</p>
359 <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>
363 <form method="post" action="install.php" class="form_settings" id="form_install">
365 <legend>Connection settings</legend>
366 <ul class="form_data">
368 <label for="sitename">Site name</label>
369 <input type="text" id="sitename" name="sitename" />
370 <p class="form_guide">The name of your site</p>
373 <label for="fancy-enable">Fancy URLs</label>
374 <input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
375 <input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
376 <p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
379 <label for="host">Hostname</label>
380 <input type="text" id="host" name="host" />
381 <p class="form_guide">Database hostname</p>
385 <label for="dbtype">Type</label>
386 <input type="radio" name="dbtype" id="fancy-mysql" value="mysql" checked='checked' /> MySQL<br />
387 <input type="radio" name="dbtype" id="dbtype-pgsql" value="pgsql" /> PostgreSQL<br />
388 <p class="form_guide">Database type</p>
392 <label for="database">Name</label>
393 <input type="text" id="database" name="database" />
394 <p class="form_guide">Database name</p>
397 <label for="username">Username</label>
398 <input type="text" id="username" name="username" />
399 <p class="form_guide">Database username</p>
402 <label for="password">Password</label>
403 <input type="password" id="password" name="password" />
404 <p class="form_guide">Database password (optional)</p>
407 <input type="submit" name="submit" class="submit" value="Submit" />
414 function updateStatus($status, $error=false)
417 <li <?php echo ($error) ? 'class="error"': ''; ?>><?php echo $status;?></li>
422 function handlePost()
427 $host = $_POST['host'];
428 $dbtype = $_POST['dbtype'];
429 $database = $_POST['database'];
430 $username = $_POST['username'];
431 $password = $_POST['password'];
432 $sitename = $_POST['sitename'];
433 $fancy = !empty($_POST['fancy']);
434 $server = $_SERVER['HTTP_HOST'];
435 $path = substr(dirname($_SERVER['PHP_SELF']), 1);
438 <dl class="system_notice">
446 updateStatus("No hostname specified.", true);
450 if (empty($database)) {
451 updateStatus("No database specified.", true);
455 if (empty($username)) {
456 updateStatus("No username specified.", true);
460 // if (empty($password)) {
461 // updateStatus("No password specified.", true);
465 if (empty($sitename)) {
466 updateStatus("No sitename specified.", true);
475 // FIXME: use PEAR::DB or PDO instead of our own switch
479 $db = mysql_db_installer($host, $database, $username, $password);
482 $db = pgsql_db_installer($host, $database, $username, $password);
488 // database connection failed, do not move on to create config file.
492 updateStatus("Writing config file...");
493 $res = writeConf($sitename, $server, $path, $fancy, $db);
496 updateStatus("Can't write config file.", true);
502 TODO https needs to be considered
504 $link = "http://".$server.'/'.$path;
506 updateStatus("StatusNet has been installed at $link");
507 updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
513 function pgsql_db_installer($host, $database, $username, $password) {
514 $connstring = "dbname=$database host=$host user=$username";
516 //No password would mean trust authentication used.
517 if (!empty($password)) {
518 $connstring .= " password=$password";
520 updateStatus("Starting installation...");
521 updateStatus("Checking database...");
522 $conn = pg_connect($connstring);
524 if ($conn ===false) {
525 updateStatus("Failed to connect to database: $connstring");
530 //ensure database encoding is UTF8
531 $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
532 if ($record->server_encoding != 'UTF8') {
533 updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
538 updateStatus("Running database script...");
539 //wrap in transaction;
540 pg_query($conn, 'BEGIN');
541 $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
543 if ($res === false) {
544 updateStatus("Can't run database script.", true);
548 foreach (array('sms_carrier' => 'SMS carrier',
549 'notice_source' => 'notice source',
550 'foreign_services' => 'foreign service')
552 updateStatus(sprintf("Adding %s data to database...", $name));
553 $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn, 'pgsql');
554 if ($res === false) {
555 updateStatus(sprintf("Can't run %d script.", $name), true);
560 pg_query($conn, 'COMMIT');
562 if (empty($password)) {
563 $sqlUrl = "pgsql://$username@$host/$database";
566 $sqlUrl = "pgsql://$username:$password@$host/$database";
569 $db = array('type' => 'pgsql', 'database' => $sqlUrl);
574 function mysql_db_installer($host, $database, $username, $password) {
575 updateStatus("Starting installation...");
576 updateStatus("Checking database...");
578 $conn = mysql_connect($host, $username, $password);
580 updateStatus("Can't connect to server '$host' as '$username'.", true);
584 updateStatus("Changing to database...");
585 $res = mysql_select_db($database, $conn);
587 updateStatus("Can't change to database.", true);
591 updateStatus("Running database script...");
592 $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
593 if ($res === false) {
594 updateStatus("Can't run database script.", true);
598 foreach (array('sms_carrier' => 'SMS carrier',
599 'notice_source' => 'notice source',
600 'foreign_services' => 'foreign service')
602 updateStatus(sprintf("Adding %s data to database...", $name));
603 $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn);
604 if ($res === false) {
605 updateStatus(sprintf("Can't run %d script.", $name), true);
611 $sqlUrl = "mysqli://$username:$password@$host/$database";
612 $db = array('type' => 'mysql', 'database' => $sqlUrl);
616 function writeConf($sitename, $server, $path, $fancy, $db)
618 // assemble configuration file in a string
620 "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
623 "\$config['site']['name'] = '$sitename';\n\n".
626 "\$config['site']['server'] = '$server';\n".
627 "\$config['site']['path'] = '$path'; \n\n".
629 // checks if fancy URLs are enabled
630 ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
633 "\$config['db']['database'] = '{$db['database']}';\n\n".
634 ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
635 "\$config['db']['type'] = '{$db['type']}';\n\n".
638 // write configuration file out to install directory
639 $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
644 function runDbScript($filename, $conn, $type = 'mysql')
646 $sql = trim(file_get_contents($filename));
647 $stmts = explode(';', $sql);
648 foreach ($stmts as $stmt) {
650 if (!mb_strlen($stmt)) {
653 // FIXME: use PEAR::DB or PDO instead of our own switch
656 $res = mysql_query($stmt, $conn);
657 if ($res === false) {
658 $error = mysql_error();
662 $res = pg_query($conn, $stmt);
663 if ($res === false) {
664 $error = pg_last_error();
668 updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
670 if ($res === false) {
671 updateStatus("ERROR ($error) for SQL '$stmt'");
679 <?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
681 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
683 <title>Install StatusNet</title>
684 <link rel="shortcut icon" href="favicon.ico"/>
685 <link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
686 <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
687 <!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
688 <!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
689 <script src="js/jquery.min.js"></script>
690 <script src="js/install.js"></script>
695 <address id="site_contact" class="vcard">
696 <a class="url home bookmark" href=".">
697 <img class="logo photo" src="theme/default/logo.png" alt="StatusNet"/>
698 <span class="fn org">StatusNet</span>
704 <h1>Install StatusNet</h1>