]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/DomainStatusNetwork/lib/domainstatusnetworkinstaller.php
Merge commit 'refs/merge-requests/199' of git://gitorious.org/statusnet/mainline...
[quix0rs-gnu-social.git] / plugins / DomainStatusNetwork / lib / domainstatusnetworkinstaller.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2011, StatusNet, Inc.
5  *
6  * Installer class for domain-based multi-homing systems
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  DomainStatusNetwork
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @copyright 2011 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     // This check helps protect against security problems;
33     // your code file can't be executed directly from the web.
34     exit(1);
35 }
36
37 /**
38  * Installer class for domain-based multi-homing systems
39  *
40  * @category  DomainStatusNetwork
41  * @package   StatusNet
42  * @author    Evan Prodromou <evan@status.net>
43  * @copyright 2011 StatusNet, Inc.
44  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
45  * @link      http://status.net/
46  */
47 class DomainStatusNetworkInstaller extends Installer
48 {
49     protected $domain   = null;
50     protected $rootname = null;
51     protected $sitedb   = null;
52     protected $rootpass = null;
53     protected $nickname = null;
54     protected $sn       = null;
55
56     public $verbose     = false;
57
58     function __construct($domain)
59     {
60         $this->domain = $domain;
61     }
62
63     /**
64      * Go for it!
65      * @return boolean success
66      */
67     function main()
68     {
69         // We don't check prereqs. Check 'em before setting up a
70         // multi-home system, kthxbi
71         if ($this->prepare()) {
72             return $this->handle();
73         } else {
74             $this->showHelp();
75             return false;
76         }
77     }
78
79     /**
80      * Get our input parameters...
81      * @return boolean success
82      */
83     function prepare()
84     {
85         $config = $this->getConfig();
86
87         $this->nickname = DomainStatusNetworkPlugin::nicknameForDomain($this->domain);
88
89         // XXX make this configurable
90
91         $this->sitename = sprintf('The %s Status Network', $this->domain);
92
93         $this->server   = $this->nickname.'.'.$config['WILDCARD'];
94         $this->path     = null;
95         $this->fancy    = true;
96
97         $datanick = $this->databaseize($this->nickname);
98
99         $this->host     = $config['DBHOSTNAME'];
100         $this->database = $datanick.$config['DBBASE'];
101         $this->dbtype   = 'mysql'; // XXX: support others... someday
102         $this->username = $datanick.$config['USERBASE'];
103
104         // Max size for MySQL
105
106         if (strlen($this->username) > 16) {
107             $this->username = sprintf('%s%08x', substr($this->username, 0, 8), crc32($this->username));
108         }
109
110         $pwgen = $config['PWDGEN'];
111
112         $password = `$pwgen`;
113
114         $this->password = trim($password);
115
116         // For setting up the database
117
118         $this->rootname = $config['ADMIN'];
119         $this->rootpass = $config['ADMINPASS'];
120         $this->sitehost = $config['SITEDBHOSTNAME'];
121         $this->sitedb   = $config['SITEDB'];
122
123         $tagstr = $config['TAGS'];
124
125         if (!empty($tagstr)) {
126             $this->tags = preg_split('/[\s,]+/', $tagstr);
127         } else {
128             $this->tags = array();
129         }
130
131         // Explicitly empty
132
133         $this->adminNick    = null;
134         $this->adminPass    = null;
135         $this->adminEmail   = null;
136         $this->adminUpdates = null;
137
138         /** Should we skip writing the configuration file? */
139         $this->skipConfig = true;
140
141         if (!$this->validateDb()) {
142             return false;
143         }
144
145         return true;
146     }
147
148     function handle()
149     {
150         return $this->doInstall();
151     }
152
153     function setupDatabase()
154     {
155         $this->updateStatus('Creating database...');
156         $this->createDatabase();
157         parent::setupDatabase();
158         $this->updateStatus('Creating file directories...');
159         $this->createDirectories();
160         $this->updateStatus('Saving status network...');
161         $this->saveStatusNetwork();
162         $this->updateStatus('Checking schema for plugins...');
163         $this->checkSchema();
164     }
165
166     function saveStatusNetwork()
167     {
168         Status_network::setupDB($this->sitehost,
169                                 $this->rootname,
170                                 $this->rootpass,
171                                 $this->sitedb, array());
172
173         $sn = new Status_network();
174
175         $sn->nickname = $this->nickname;
176         $sn->dbhost   = $this->host;
177         $sn->dbuser   = $this->username;
178         $sn->dbpass   = $this->password;
179         $sn->dbname   = $this->database;
180         $sn->sitename = $this->sitename;
181         $sn->created  = common_sql_now();
182
183         $result = $sn->insert();
184
185         if (!$result) {
186             throw new ServerException("Could not create status_network: " . print_r($sn, true));
187         }
188
189         // Re-fetch; stupid auto-increment integer isn't working
190
191         $sn = Status_network::getKV('nickname', $sn->nickname);
192
193         if (empty($sn)) {
194             throw new ServerException("Created {$this->nickname} status_network and could not find it again.");
195         }
196
197         // Set default tags
198
199         $tags = $this->tags;
200
201         // Add domain tag
202
203         $tags[] = 'domain='.$this->domain;
204
205         $sn->setTags($tags);
206
207         $this->sn = $sn;
208     }
209
210     function checkSchema()
211     {
212         $config = $this->getConfig();
213
214         Status_network::$wildcard = $config['WILDCARD'];
215
216         StatusNet::switchSite($this->nickname);
217
218         // We need to initialize the schema_version stuff to make later setup easier
219
220         $schema = array();
221         require INSTALLDIR.'/db/core.php';
222         $tableDefs = $schema;
223
224         $schema = Schema::get();
225         $schemaUpdater = new SchemaUpdater($schema);
226
227         foreach ($tableDefs as $table => $def) {
228             $schemaUpdater->register($table, $def);
229         }
230
231         $schemaUpdater->checkSchema();
232
233         Event::handle('CheckSchema');
234     }
235
236     function getStatusNetwork()
237     {
238         return $this->sn;
239     }
240
241     function createDirectories()
242     {
243         $config = $this->getConfig();
244
245         foreach (array('AVATARBASE', 'BACKGROUNDBASE', 'FILEBASE') as $key) {
246             $base = $config[$key];
247             $dirname = $base.'/'.$this->nickname;
248
249             // Make sure our bits are set
250             $mask = umask(0);
251             mkdir($dirname, 0770, true);
252             umask($mask);
253
254             // If you set the setuid bit on your base dirs this should be
255             // unnecessary, but just in case. You must be root for this
256             // to work.
257
258             if (array_key_exists('WEBUSER', $config)) {
259                 chown($dirname, $config['WEBUSER']);
260             }
261             if (array_key_exists('WEBGROUP', $config)) {
262                 chgrp($dirname, $config['WEBGROUP']);
263             }
264         }
265     }
266
267     function createDatabase()
268     {
269         // Create the New DB
270         /* FIXME
271          * Extension 'mysql_' is deprecated since PHP 5.5 - use mysqli instead.
272          */
273         $res = mysql_connect($this->host, $this->rootname, $this->rootpass);
274         if (!$res) {
275             throw new ServerException("Cannot connect to {$this->host} as {$this->rootname}.");
276         }
277
278         mysql_query("CREATE DATABASE ". mysql_real_escape_string($this->database), $res);
279
280         $return = mysql_select_db($this->database, $res);
281
282         if (!$return) {
283             throw new ServerException("Unable to connect to {$this->database} on {$this->host}.");
284         }
285
286         foreach (array('localhost', '%') as $src) {
287             mysql_query("GRANT ALL ON " .
288                         mysql_real_escape_string($this->database).".* TO '" .
289                         $this->username . "'@'".$src."' ".
290                         "IDENTIFIED BY '".$this->password."'", $res);
291         }
292
293         mysql_close($res);
294     }
295
296     function getConfig()
297     {
298         static $config;
299
300         $cfg_file = "/etc/statusnet/setup.cfg";
301
302         if (empty($config)) {
303             $result = parse_ini_file($cfg_file);
304
305             $config = array();
306             foreach ($result as $key => $value) {
307                 $key = str_replace('export ', '', $key);
308                 $config[$key] = $value;
309             }
310         }
311
312         return $config;
313     }
314
315     function showHelp()
316     {
317     }
318
319     function warning($message, $submessage='')
320     {
321         print $this->html2text($message) . "\n";
322         if ($submessage != '') {
323             print "  " . $this->html2text($submessage) . "\n";
324         }
325         print "\n";
326     }
327
328     function updateStatus($status, $error=false)
329     {
330         if ($this->verbose || $error) {
331             if ($error) {
332                 print "ERROR: ";
333             }
334             print $this->html2text($status);
335             print "\n";
336         }
337     }
338
339     private function html2text($html)
340     {
341         // break out any links for text legibility
342         $breakout = preg_replace('/<a[^>+]\bhref="(.*)"[^>]*>(.*)<\/a>/',
343                                  '\2 &lt;\1&gt;',
344                                  $html);
345         return html_entity_decode(strip_tags($breakout), ENT_QUOTES, 'UTF-8');
346     }
347
348     function databaseize($nickname)
349     {
350         $nickname = str_replace('-', '_', $nickname);
351         return $nickname;
352     }
353 }