[DATABASE] Always quote identifiers

The code used to operate under the assumption that MariaDB doesn't support
quoting identifiers. Not only is that not exactly true, but MariaDB has
reserved keywords that cannot be used as table or column names unquoted.
This commit is contained in:
Alexei Sorokin 2019-09-11 08:15:16 +03:00
parent b89f1ad7d8
commit 5b797328f2
18 changed files with 1335 additions and 1191 deletions

View File

@ -178,9 +178,6 @@ The ones that you may want to set are listed below for clarity.
'MDB2' to use the other driver type for DB_DataObject, but note that it 'MDB2' to use the other driver type for DB_DataObject, but note that it
breaks the OpenID libraries, which only support PEAR::DB. breaks the OpenID libraries, which only support PEAR::DB.
* `quote_identifiers`(boolean, default false): Set this to true if you're using
postgresql.
* `type` (enum["mysql", "postgresql"], default 'mysql'): Used for certain * `type` (enum["mysql", "postgresql"], default 'mysql'): Used for certain
database-specific optimization code. Assumes mysql if not set. MySQL also database-specific optimization code. Assumes mysql if not set. MySQL also
covers MySQLi and MariaDB. covers MySQLi and MariaDB.

View File

@ -1,36 +1,31 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* List of featured users * List of featured users
* *
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public * @category Public
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
require_once INSTALLDIR . '/lib/profile/profilelist.php'; require_once INSTALLDIR . '/lib/profile/profilelist.php';
require_once INSTALLDIR . '/lib/groups/publicgroupnav.php'; require_once INSTALLDIR . '/lib/groups/publicgroupnav.php';
@ -38,23 +33,19 @@ require_once INSTALLDIR . '/lib/groups/publicgroupnav.php';
/** /**
* List of featured users * List of featured users
* *
* @category Public * @copyright 2008-2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Zach Copley <zach@status.net>
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/ */
class FeaturedAction extends Action class FeaturedAction extends Action
{ {
var $page = null; public $page = null;
function isReadOnly($args) public function isReadOnly($args)
{ {
return true; return true;
} }
function prepare(array $args = array()) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
@ -62,7 +53,7 @@ class FeaturedAction extends Action
return true; return true;
} }
function title() public function title()
{ {
if ($this->page == 1) { if ($this->page == 1) {
// TRANS: Page title for first page of featured users. // TRANS: Page title for first page of featured users.
@ -74,14 +65,14 @@ class FeaturedAction extends Action
} }
} }
function handle() public function handle()
{ {
parent::handle(); parent::handle();
$this->showPage(); $this->showPage();
} }
function showPageNotice() public function showPageNotice()
{ {
$instr = $this->getInstructions(); $instr = $this->getInstructions();
$output = common_markup_to_html($instr); $output = common_markup_to_html($instr);
@ -90,14 +81,16 @@ class FeaturedAction extends Action
$this->elementEnd('div'); $this->elementEnd('div');
} }
function getInstructions() public function getInstructions()
{ {
// TRANS: Description on page displaying featured users. // TRANS: Description on page displaying featured users.
return sprintf(_('A selection of some great users on %s.'), return sprintf(
common_config('site', 'name')); _('A selection of some great users on %s.'),
common_config('site', 'name')
);
} }
function showContent() public function showContent()
{ {
// XXX: Note I'm doing it this two-stage way because a raw query // XXX: Note I'm doing it this two-stage way because a raw query
// with a JOIN was *not* working. --Zach // with a JOIN was *not* working. --Zach
@ -105,7 +98,6 @@ class FeaturedAction extends Action
$featured_nicks = common_config('nickname', 'featured'); $featured_nicks = common_config('nickname', 'featured');
if (count($featured_nicks) > 0) { if (count($featured_nicks) > 0) {
$quoted = array(); $quoted = array();
foreach ($featured_nicks as $nick) { foreach ($featured_nicks as $nick) {
@ -115,7 +107,7 @@ class FeaturedAction extends Action
$user = new User; $user = new User;
$user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted))); $user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted)));
$user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1); $user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
$user->orderBy(common_database_tablename('user') .'.nickname ASC'); $user->orderBy($user->escapedTableName() . '.nickname ASC');
$user->find(); $user->find();
@ -138,8 +130,12 @@ class FeaturedAction extends Action
$profile->free(); $profile->free();
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, $this->pagination(
$this->page, 'featured'); $this->page > 1,
$cnt > PROFILES_PER_PAGE,
$this->page,
'featured'
);
} }
} }
} }

View File

@ -1,29 +1,26 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* GNU social - a federating social network
*
* Abstraction for files
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Files * @category Files
* @package GNUsocial * @package GNUsocial
* @author Mikael Nordfeldth <mmn@hethane.se> * @author Mikael Nordfeldth <mmn@hethane.se>
* @author Miguel Dantas <biodantas@gmail.com> * @author Miguel Dantas <biodantas@gmail.com>
* @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org * @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link https://www.gnu.org/software/social/
*/ */
defined('GNUSOCIAL') || die(); defined('GNUSOCIAL') || die();
@ -346,7 +343,8 @@ class File extends Managed_DataObject
* @param string $filename * @param string $filename
* @return string|bool Value from the 'extblacklist' array, in the config * @return string|bool Value from the 'extblacklist' array, in the config
*/ */
public static function getSafeExtension(string $filename) { public static function getSafeExtension(string $filename)
{
if (preg_match('/^.+?\.([A-Za-z0-9]+)$/', $filename, $matches) === 1) { if (preg_match('/^.+?\.([A-Za-z0-9]+)$/', $filename, $matches) === 1) {
// we matched on a file extension, so let's see if it means something. // we matched on a file extension, so let's see if it means something.
$ext = mb_strtolower($matches[1]); $ext = mb_strtolower($matches[1]);
@ -888,7 +886,11 @@ class File extends Managed_DataObject
echo "\nFound old $table table, upgrading it to contain 'urlhash' field..."; echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
$file = new File(); $file = new File();
$file->query(sprintf('SELECT id, LEFT(url, 191) AS shortenedurl, COUNT(*) AS c FROM %1$s WHERE LENGTH(url)>191 GROUP BY shortenedurl HAVING c > 1', $schema->quoteIdentifier($table))); $file->query(sprintf(
'SELECT id, LEFT(url, 191) AS shortenedurl, COUNT(*) FROM %1$s ' .
'WHERE LENGTH(url) > 191 GROUP BY id, shortenedurl HAVING COUNT(*) > 1',
common_database_tablename($table)
));
print "\nFound {$file->N} URLs with too long entries in file table\n"; print "\nFound {$file->N} URLs with too long entries in file table\n";
while ($file->fetch()) { while ($file->fetch()) {
// We've got a URL that is too long for our future file table // We've got a URL that is too long for our future file table
@ -943,11 +945,10 @@ class File extends Managed_DataObject
echo "Updating urlhash fields in $table table..."; echo "Updating urlhash fields in $table table...";
// Maybe very MySQL specific :( // Maybe very MySQL specific :(
$tablefix->query(sprintf( $tablefix->query(sprintf(
'UPDATE %1$s SET %2$s=%3$s;', 'UPDATE %1$s SET urlhash = %2$s;',
$schema->quoteIdentifier($table), $tablefix->escapedTableName(),
'urlhash',
// The line below is "result of sha256 on column `url`" // The line below is "result of sha256 on column `url`"
'SHA2(url, 256)' 'sha2(url, 256)'
)); ));
echo "DONE.\n"; echo "DONE.\n";
echo "Resuming core schema upgrade..."; echo "Resuming core schema upgrade...";

View File

@ -1,23 +1,20 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
* GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License
* // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for file_redirection * Table Definition for file_redirection
@ -59,12 +56,13 @@ class File_redirection extends Managed_DataObject
); );
} }
static public function getByUrl($url) public static function getByUrl($url)
{ {
return self::getByPK(array('urlhash' => File::hashurl($url))); return self::getByPK(array('urlhash' => File::hashurl($url)));
} }
static function _commonHttp($url, $redirs) { public static function _commonHttp($url, $redirs)
{
$request = new HTTPClient($url); $request = new HTTPClient($url);
$request->setConfig(array( $request->setConfig(array(
'connect_timeout' => 10, // # seconds to wait 'connect_timeout' => 10, // # seconds to wait
@ -96,8 +94,11 @@ class File_redirection extends Managed_DataObject
* size (optional): byte size from Content-Length header * size (optional): byte size from Content-Length header
* time (optional): timestamp from Last-Modified header * time (optional): timestamp from Last-Modified header
*/ */
static function lookupWhere($short_url, $redirs = 10, $protected = false) { public static function lookupWhere($short_url, $redirs = 10, $protected = false)
if ($redirs < 0) return false; {
if ($redirs < 0) {
return false;
}
if (strpos($short_url, '://') === false) { if (strpos($short_url, '://') === false) {
return $short_url; return $short_url;
@ -142,12 +143,20 @@ class File_redirection extends Managed_DataObject
, 'url' => $return_url); , 'url' => $return_url);
$type = $response->getHeader('Content-Type'); $type = $response->getHeader('Content-Type');
if ($type) $ret['type'] = $type; if ($type) {
if ($protected) $ret['protected'] = true; $ret['type'] = $type;
}
if ($protected) {
$ret['protected'] = true;
}
$size = $response->getHeader('Content-Length'); // @fixme bytes? $size = $response->getHeader('Content-Length'); // @fixme bytes?
if ($size) $ret['size'] = $size; if ($size) {
$ret['size'] = $size;
}
$time = $response->getHeader('Last-Modified'); $time = $response->getHeader('Last-Modified');
if ($time) $ret['time'] = strtotime($time); if ($time) {
$ret['time'] = strtotime($time);
}
return $ret; return $ret;
} }
@ -164,7 +173,8 @@ class File_redirection extends Managed_DataObject
* @param boolean $discover true to attempt dereferencing the redirect if we don't know it already * @param boolean $discover true to attempt dereferencing the redirect if we don't know it already
* @return File_redirection * @return File_redirection
*/ */
static function where($in_url, $discover=true) { public static function where($in_url, $discover = true)
{
$redir = new File_redirection(); $redir = new File_redirection();
$redir->url = $in_url; $redir->url = $in_url;
$redir->urlhash = File::hashurl($redir->url); $redir->urlhash = File::hashurl($redir->url);
@ -179,14 +189,16 @@ class File_redirection extends Managed_DataObject
$r->redir_url = $f->url; $r->redir_url = $f->url;
} catch (NoResultException $e) { } catch (NoResultException $e) {
// Invalid entry, delete and run again // Invalid entry, delete and run again
common_log(LOG_ERR, "Could not find File with id=".$r->file_id." referenced in File_redirection, deleting File redirection entry and and trying again..."); common_log(
LOG_ERR,
'Could not find File with id=' . $r->file_id . ' referenced in File_redirection, deleting File redirection entry and and trying again...'
);
$r->delete(); $r->delete();
return self::where($in_url); return self::where($in_url);
} }
// File_redirecion and File record found, return both // File_redirecion and File record found, return both
return $r; return $r;
} catch (NoResultException $e) { } catch (NoResultException $e) {
// File_redirecion record not found, but this might be a direct link to a file // File_redirecion record not found, but this might be a direct link to a file
try { try {
@ -219,7 +231,10 @@ class File_redirection extends Managed_DataObject
$redir->redir_url = $f->url; $redir->redir_url = $f->url;
} else { } else {
// Invalid entry in File_redirection, delete and run again // Invalid entry in File_redirection, delete and run again
common_log(LOG_ERR, "Could not find File with id=".$r->file_id." referenced in File_redirection, deleting File_redirection entry and trying again..."); common_log(
LOG_ERR,
'Could not find File with id=' . $r->file_id . ' referenced in File_redirection, deleting File_redirection entry and trying again...'
);
$r->delete(); $r->delete();
return self::where($in_url); return self::where($in_url);
} }
@ -268,7 +283,7 @@ class File_redirection extends Managed_DataObject
* @param User $user whose shortening options to use; defaults to the current web session user * @param User $user whose shortening options to use; defaults to the current web session user
* @return string * @return string
*/ */
static function makeShort($long_url, $user=null) public static function makeShort($long_url, $user = null)
{ {
$canon = File_redirection::_canonUrl($long_url); $canon = File_redirection::_canonUrl($long_url);
@ -293,7 +308,7 @@ class File_redirection extends Managed_DataObject
* @return string * @return string
*/ */
static function forceShort($long_url, $user) public static function forceShort($long_url, $user)
{ {
$canon = File_redirection::_canonUrl($long_url); $canon = File_redirection::_canonUrl($long_url);
@ -303,7 +318,8 @@ class File_redirection extends Managed_DataObject
return !empty($short_url) ? $short_url : $long_url; return !empty($short_url) ? $short_url : $long_url;
} }
static function _userMakeShort($long_url, User $user=null, $force = false) { public static function _userMakeShort($long_url, User $user = null, $force = false)
{
$short_url = common_shorten_url($long_url, $user, $force); $short_url = common_shorten_url($long_url, $user, $force);
if (!empty($short_url) && $short_url != $long_url) { if (!empty($short_url) && $short_url != $long_url) {
$short_url = (string)$short_url; $short_url = (string)$short_url;
@ -343,8 +359,11 @@ class File_redirection extends Managed_DataObject
* @param string $default_scheme if given a bare link; defaults to 'http://' * @param string $default_scheme if given a bare link; defaults to 'http://'
* @return string * @return string
*/ */
static function _canonUrl($in_url, $default_scheme = 'http://') { public static function _canonUrl($in_url, $default_scheme = 'http://')
if (empty($in_url)) return false; {
if (empty($in_url)) {
return false;
}
$out_url = $in_url; $out_url = $in_url;
$p = parse_url($out_url); $p = parse_url($out_url);
if (empty($p['host']) || empty($p['scheme'])) { if (empty($p['host']) || empty($p['scheme'])) {
@ -377,13 +396,17 @@ class File_redirection extends Managed_DataObject
default: default:
$out_url = $default_scheme . ltrim($out_url, '/'); $out_url = $default_scheme . ltrim($out_url, '/');
$p = parse_url($out_url); $p = parse_url($out_url);
if (empty($p['scheme'])) return false; if (empty($p['scheme'])) {
return false;
}
break; break;
} }
} }
if (('ftp' == $p['scheme']) || ('ftps' == $p['scheme']) || ('http' == $p['scheme']) || ('https' == $p['scheme'])) { if (('ftp' == $p['scheme']) || ('ftps' == $p['scheme']) || ('http' == $p['scheme']) || ('https' == $p['scheme'])) {
if (empty($p['host'])) return false; if (empty($p['host'])) {
return false;
}
if (empty($p['path'])) { if (empty($p['path'])) {
$out_url .= '/'; $out_url .= '/';
} }
@ -392,7 +415,8 @@ class File_redirection extends Managed_DataObject
return $out_url; return $out_url;
} }
static function saveNew($data, $file_id, $url) { public static function saveNew($data, $file_id, $url)
{
$file_redir = new File_redirection; $file_redir = new File_redirection;
$file_redir->urlhash = File::hashurl($url); $file_redir->urlhash = File::hashurl($url);
$file_redir->url = $url; $file_redir->url = $url;
@ -402,7 +426,7 @@ class File_redirection extends Managed_DataObject
$file_redir->insert(); $file_redir->insert();
} }
static public function beforeSchemaUpdate() public static function beforeSchemaUpdate()
{ {
$table = strtolower(get_called_class()); $table = strtolower(get_called_class());
$schema = Schema::get(); $schema = Schema::get();
@ -416,16 +440,16 @@ class File_redirection extends Managed_DataObject
echo "\nFound old $table table, upgrading it to contain 'urlhash' field..."; echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
// We have to create a urlhash that is _not_ the primary key, // We have to create a urlhash that is _not_ the primary key,
// transfer data and THEN run checkSchema // transfer data and THEN run checkSchema
$schemadef['fields']['urlhash'] = array ( $schemadef['fields']['urlhash'] = [
'type' => 'varchar', 'type' => 'varchar',
'length' => 64, 'length' => 64,
'not null' => true, 'not null' => true,
'description' => 'sha256 hash of the URL', 'description' => 'sha256 hash of the URL',
); ];
$schemadef['fields']['url'] = array ( $schemadef['fields']['url'] = [
'type' => 'text', 'type' => 'text',
'description' => 'short URL (or any other kind of redirect) for file (id)', 'description' => 'short URL (or any other kind of redirect) for file (id)',
); ];
unset($schemadef['primary key']); unset($schemadef['primary key']);
$schema->ensureTable($table, $schemadef); $schema->ensureTable($table, $schemadef);
echo "DONE.\n"; echo "DONE.\n";
@ -435,16 +459,18 @@ class File_redirection extends Managed_DataObject
// urlhash is hash('sha256', $url) in the File table // urlhash is hash('sha256', $url) in the File table
echo "Updating urlhash fields in $table table..."; echo "Updating urlhash fields in $table table...";
// Maybe very MySQL specific :( // Maybe very MySQL specific :(
$tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;', $tablefix->query(sprintf(
$schema->quoteIdentifier($table), 'UPDATE %1$s SET urlhash = %2$s;',
'urlhash', $tablefix->escapedTableName(),
// The line below is "result of sha256 on column `url`" // The line below is "result of sha256 on column `url`"
'SHA2(url, 256)')); 'sha2(url, 256)'
));
echo "DONE.\n"; echo "DONE.\n";
echo "Resuming core schema upgrade..."; echo "Resuming core schema upgrade...";
} }
public function getFile() { public function getFile()
{
if (!$this->file instanceof File) { if (!$this->file instanceof File) {
$this->file = File::getByID($this->file_id); $this->file = File::getByID($this->file_id);
} }

View File

@ -1,28 +1,31 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2010, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
* GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License
* // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** /**
* Wrapper for Memcached_DataObject which knows its own schema definition. * Wrapper for Memcached_DataObject which knows its own schema definition.
* Builds its own damn settings from a schema definition. * Builds its own damn settings from a schema definition.
* *
* @package GNUsocial
* @author Brion Vibber <brion@status.net> * @author Brion Vibber <brion@status.net>
* @copyright 2010 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
defined('GNUSOCIAL') || die();
abstract class Managed_DataObject extends Memcached_DataObject abstract class Managed_DataObject extends Memcached_DataObject
{ {
/** /**
@ -42,7 +45,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return get_called_class() object if found, or null for no hits * @return get_called_class() object if found, or null for no hits
* *
*/ */
static function getKV($k,$v=NULL) public static function getKV($k, $v = null)
{ {
return parent::getClassKV(get_called_class(), $k, $v); return parent::getClassKV(get_called_class(), $k, $v);
} }
@ -59,12 +62,12 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return get_called_class() object if found, or null for no hits * @return get_called_class() object if found, or null for no hits
* *
*/ */
static function pkeyGet(array $kv) public static function pkeyGet(array $kv)
{ {
return parent::pkeyGetClass(get_called_class(), $kv); return parent::pkeyGetClass(get_called_class(), $kv);
} }
static function pkeyCols() public static function pkeyCols()
{ {
return parent::pkeyColsClass(get_called_class()); return parent::pkeyColsClass(get_called_class());
} }
@ -78,7 +81,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* *
* @return array Array of objects, in order * @return array Array of objects, in order
*/ */
static function multiGet($keyCol, array $keyVals, $skipNulls=true) public static function multiGet($keyCol, array $keyVals, $skipNulls = true)
{ {
return parent::multiGetClass(get_called_class(), $keyCol, $keyVals, $skipNulls); return parent::multiGetClass(get_called_class(), $keyCol, $keyVals, $skipNulls);
} }
@ -92,7 +95,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* *
* @return array Array mapping $keyVals to objects, or null if not found * @return array Array mapping $keyVals to objects, or null if not found
*/ */
static function pivotGet($keyCol, array $keyVals, array $otherCols=array()) public static function pivotGet($keyCol, array $keyVals, array $otherCols = [])
{ {
return parent::pivotGetClass(get_called_class(), $keyCol, $keyVals, $otherCols); return parent::pivotGetClass(get_called_class(), $keyCol, $keyVals, $otherCols);
} }
@ -110,7 +113,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* Exception is thrown when no entries are found. * Exception is thrown when no entries are found.
* *
*/ */
static function listFind($keyCol, array $keyVals) public static function listFind($keyCol, array $keyVals)
{ {
return parent::listFindClass(get_called_class(), $keyCol, $keyVals); return parent::listFindClass(get_called_class(), $keyCol, $keyVals);
} }
@ -128,7 +131,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return array with an get_called_class() object for each $keyVals entry * @return array with an get_called_class() object for each $keyVals entry
* *
*/ */
static function listGet($keyCol, array $keyVals) public static function listGet($keyCol, array $keyVals)
{ {
return parent::listGetClass(get_called_class(), $keyCol, $keyVals); return parent::listGetClass(get_called_class(), $keyCol, $keyVals);
} }
@ -153,7 +156,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @access private * @access private
* @return array * @return array
*/ */
function keys() public function keys()
{ {
return array_keys($this->keyTypes()); return array_keys($this->keyTypes());
} }
@ -167,7 +170,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return array (column,use_native,sequence_name) * @return array (column,use_native,sequence_name)
*/ */
function sequenceKey() public function sequenceKey()
{ {
$table = static::schemaDef(); $table = static::schemaDef();
foreach ($table['fields'] as $name => $column) { foreach ($table['fields'] as $name => $column) {
@ -191,7 +194,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return array key definitions * @return array key definitions
*/ */
function keyTypes() public function keyTypes()
{ {
$table = static::schemaDef(); $table = static::schemaDef();
$keys = array(); $keys = array();
@ -218,7 +221,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @param array $column * @param array $column
* @return int * @return int
*/ */
function columnBitmap($column) public function columnBitmap($column)
{ {
$type = $column['type']; $type = $column['type'];
@ -254,7 +257,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
return $style; return $style;
} }
function links() public function links()
{ {
$links = array(); $links = array();
@ -277,7 +280,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* *
* @return array of strings * @return array of strings
*/ */
function _allCacheKeys() public function _allCacheKeys()
{ {
$table = static::schemaDef(); $table = static::schemaDef();
$ckeys = array(); $ckeys = array();
@ -322,7 +325,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return Managed_DataObject of the get_called_class() type * @return Managed_DataObject of the get_called_class() type
* @throws NoResultException if no object with that primary key * @throws NoResultException if no object with that primary key
*/ */
static function getByPK(array $vals) public static function getByPK(array $vals)
{ {
$classname = get_called_class(); $classname = get_called_class();
@ -356,7 +359,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return Managed_DataObject of the get_called_class() type * @return Managed_DataObject of the get_called_class() type
* @throws NoResultException if no object with that primary key * @throws NoResultException if no object with that primary key
*/ */
static function getByKeys(array $vals) public static function getByKeys(array $vals)
{ {
$classname = get_called_class(); $classname = get_called_class();
@ -381,7 +384,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
return $object; return $object;
} }
static function getByID($id) public static function getByID($id)
{ {
if (!property_exists(get_called_class(), 'id')) { if (!property_exists(get_called_class(), 'id')) {
throw new ServerException('Trying to get undefined property of dataobject class.'); throw new ServerException('Trying to get undefined property of dataobject class.');
@ -394,7 +397,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
return static::getByPK(array('id' => $id)); return static::getByPK(array('id' => $id));
} }
static function getByUri($uri) public static function getByUri($uri)
{ {
if (!property_exists(get_called_class(), 'uri')) { if (!property_exists(get_called_class(), 'uri')) {
throw new ServerException('Trying to get undefined property of dataobject class.'); throw new ServerException('Trying to get undefined property of dataobject class.');
@ -537,7 +540,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
$pid = $schema['primary key']; $pid = $schema['primary key'];
unset($schema); unset($schema);
} }
$pidWhere = array(); $pidWhere = [];
foreach ((array) $pid as $pidCol) { foreach ((array) $pid as $pidCol) {
$pidWhere[] = sprintf('%1$s = %2$s', $pidCol, $this->_quote($orig->$pidCol)); $pidWhere[] = sprintf('%1$s = %2$s', $pidCol, $this->_quote($orig->$pidCol));
} }
@ -545,10 +548,12 @@ abstract class Managed_DataObject extends Memcached_DataObject
throw new ServerException('No primary ID column(s) set for updateWithKeys'); throw new ServerException('No primary ID column(s) set for updateWithKeys');
} }
$qry = sprintf('UPDATE %1$s SET %2$s WHERE %3$s', $qry = sprintf(
common_database_tablename($this->tableName()), 'UPDATE %1$s SET %2$s WHERE %3$s',
$this->escapedTableName(),
implode(', ', $parts), implode(', ', $parts),
implode(' AND ', $pidWhere)); implode(' AND ', $pidWhere)
);
$result = $this->query($qry); $result = $this->query($qry);
if ($result === false) { if ($result === false) {
@ -576,21 +581,23 @@ abstract class Managed_DataObject extends Memcached_DataObject
return $result; return $result;
} }
static public function beforeSchemaUpdate() public static function beforeSchemaUpdate()
{ {
// NOOP // NOOP
} }
static function newUri(Profile $actor, Managed_DataObject $object, $created=null) public static function newUri(Profile $actor, Managed_DataObject $object, $created = null)
{ {
if (is_null($created)) { if (is_null($created)) {
$created = common_sql_now(); $created = common_sql_now();
} }
return TagURI::mint(strtolower(get_called_class()).':%d:%s:%d:%s', return TagURI::mint(
strtolower(get_called_class()) . ':%d:%s:%d:%s',
$actor->getID(), $actor->getID(),
ActivityUtils::resolveUri($object->getObjectType(), true), ActivityUtils::resolveUri($object->getObjectType(), true),
$object->getID(), $object->getID(),
common_date_iso8601($created)); common_date_iso8601($created)
);
} }
protected function onInsert() protected function onInsert()

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,26 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
/** /**
* Table Definition for oauth_application_user * Table Definition for oauth_application_user
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Oauth_application_user extends Managed_DataObject class Oauth_application_user extends Managed_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
@ -39,7 +56,7 @@ class Oauth_application_user extends Managed_DataObject
); );
} }
static function getByUserAndToken($user, $token) public static function getByUserAndToken($user, $token)
{ {
if (empty($user) || empty($token)) { if (empty($user) || empty($token)) {
return null; return null;
@ -56,7 +73,7 @@ class Oauth_application_user extends Managed_DataObject
return empty($result) ? null : $oau; return empty($result) ? null : $oau;
} }
function updateKeys(&$orig) public function updateKeys(&$orig)
{ {
$this->_connect(); $this->_connect();
$parts = array(); $parts = array();
@ -72,13 +89,11 @@ class Oauth_application_user extends Managed_DataObject
$toupdate = implode(', ', $parts); $toupdate = implode(', ', $parts);
$table = $this->tableName(); $table = $this->tableName();
if(common_config('db','quote_identifiers')) { $tableName = $this->escapedTableName();
$table = '"' . $table . '"'; $qry = 'UPDATE ' . $tableName . ' SET ' . $toupdate .
} ' WHERE profile_id = ' . $orig->profile_id .
$qry = 'UPDATE ' . $table . ' SET ' . $toupdate . ' AND application_id = ' . $orig->application_id .
' WHERE profile_id = ' . $orig->profile_id " AND token = '" . $orig->token . "'";
. ' AND application_id = ' . $orig->application_id
. " AND token = '$orig->token'";
$orig->decache(); $orig->decache();
$result = $this->query($qry); $result = $this->query($qry);
if ($result) { if ($result) {

View File

@ -1,27 +1,28 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Notices * @category Notices
* @package StatusNet * @package GNUsocial
* @author Shashi Gowda <connect2shashi@gmail.com> * @author Shashi Gowda <connect2shashi@gmail.com>
* @license GNU Affero General Public License http://www.gnu.org/licenses/ * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
class Profile_list extends Managed_DataObject class Profile_list extends Managed_DataObject
{ {
@ -79,7 +80,7 @@ class Profile_list extends Managed_DataObject
* @return Profile the tagger * @return Profile the tagger
*/ */
function getTagger() public function getTagger()
{ {
return Profile::getByID($this->tagger); return Profile::getByID($this->tagger);
} }
@ -91,7 +92,7 @@ class Profile_list extends Managed_DataObject
* @return String * @return String
*/ */
function getBestName() public function getBestName()
{ {
return $this->tag; return $this->tag;
} }
@ -102,15 +103,17 @@ class Profile_list extends Managed_DataObject
* @return String uri * @return String uri
*/ */
function getUri() public function getUri()
{ {
$uri = null; $uri = null;
if (Event::handle('StartProfiletagGetUri', array($this, &$uri))) { if (Event::handle('StartProfiletagGetUri', array($this, &$uri))) {
if (!empty($this->uri)) { if (!empty($this->uri)) {
$uri = $this->uri; $uri = $this->uri;
} else { } else {
$uri = common_local_url('profiletagbyid', $uri = common_local_url(
array('id' => $this->id, 'tagger_id' => $this->tagger)); 'profiletagbyid',
['id' => $this->id, 'tagger_id' => $this->tagger]
);
} }
} }
Event::handle('EndProfiletagGetUri', array($this, &$uri)); Event::handle('EndProfiletagGetUri', array($this, &$uri));
@ -123,7 +126,7 @@ class Profile_list extends Managed_DataObject
* @return String home url * @return String home url
*/ */
function homeUrl() public function homeUrl()
{ {
$url = null; $url = null;
if (Event::handle('StartUserPeopletagHomeUrl', array($this, &$url))) { if (Event::handle('StartUserPeopletagHomeUrl', array($this, &$url))) {
@ -131,9 +134,13 @@ class Profile_list extends Managed_DataObject
if (!empty($this->mainpage)) { if (!empty($this->mainpage)) {
$url = $this->mainpage; $url = $this->mainpage;
} else { } else {
$url = common_local_url('showprofiletag', $url = common_local_url(
array('nickname' => $this->getTagger()->nickname, 'showprofiletag',
'tag' => $this->tag)); [
'nickname' => $this->getTagger()->nickname,
'tag' => $this->tag,
]
);
} }
} }
Event::handle('EndUserPeopletagHomeUrl', array($this, &$url)); Event::handle('EndUserPeopletagHomeUrl', array($this, &$url));
@ -146,12 +153,14 @@ class Profile_list extends Managed_DataObject
* @return String permalink * @return String permalink
*/ */
function permalink() public function permalink()
{ {
$url = null; $url = null;
if (Event::handle('StartProfiletagPermalink', array($this, &$url))) { if (Event::handle('StartProfiletagPermalink', array($this, &$url))) {
$url = common_local_url('profiletagbyid', $url = common_local_url(
array('id' => $this->id)); 'profiletagbyid',
['id' => $this->id]
);
} }
Event::handle('EndProfiletagPermalink', array($this, &$url)); Event::handle('EndProfiletagPermalink', array($this, &$url));
return $url; return $url;
@ -169,7 +178,7 @@ class Profile_list extends Managed_DataObject
* @return Notice the query * @return Notice the query
*/ */
function getNotices($offset, $limit, $since_id=null, $max_id=null) public function getNotices($offset, $limit, $since_id = null, $max_id = null)
{ {
// FIXME: Use something else than Profile::current() to avoid // FIXME: Use something else than Profile::current() to avoid
// possible confusion between session user and queue processing. // possible confusion between session user and queue processing.
@ -190,7 +199,7 @@ class Profile_list extends Managed_DataObject
* @return Profile results * @return Profile results
*/ */
function getSubscribers($offset=0, $limit=null, $since=0, $upto=0) public function getSubscribers($offset = 0, $limit = null, $since = 0, $upto = 0)
{ {
$subs = new Profile(); $subs = new Profile();
@ -227,24 +236,22 @@ class Profile_list extends Managed_DataObject
* @return array ids of users * @return array ids of users
*/ */
function getUserSubscribers() public function getUserSubscribers()
{ {
// XXX: cache this // XXX: cache this
$user = new User(); $user = new User();
if(common_config('db','quote_identifiers'))
$user_table = '"user"';
else $user_table = 'user';
$qry = $user->query(sprintf(
'SELECT id ' . 'SELECT id ' .
'FROM '. $user_table .' JOIN profile_tag_subscription '. 'FROM %1$s INNER JOIN profile_tag_subscription ' .
'ON '. $user_table .'.id = profile_tag_subscription.profile_id ' . 'ON %1$s.id = profile_tag_subscription.profile_id ' .
'WHERE profile_tag_subscription.profile_tag_id = %d '; 'WHERE profile_tag_subscription.profile_tag_id = %2$d ',
$user->escapedTableName(),
$this->id
));
$user->query(sprintf($qry, $this->id)); $ids = [];
$ids = array();
while ($user->fetch()) { while ($user->fetch()) {
$ids[] = $user->id; $ids[] = $user->id;
@ -264,7 +271,7 @@ class Profile_list extends Managed_DataObject
* @return boolean subscription status * @return boolean subscription status
*/ */
function hasSubscriber($id) public function hasSubscriber($id)
{ {
if (!is_numeric($id)) { if (!is_numeric($id)) {
$id = $id->id; $id = $id->id;
@ -288,7 +295,7 @@ class Profile_list extends Managed_DataObject
* @return Profile results * @return Profile results
*/ */
function getTagged($offset=0, $limit=null, $since=0, $upto=0) public function getTagged($offset = 0, $limit = null, $since = 0, $upto = 0)
{ {
$tagged = new Profile(); $tagged = new Profile();
$tagged->joinAdd(array('id', 'profile_tag:tagged')); $tagged->joinAdd(array('id', 'profile_tag:tagged'));
@ -323,7 +330,7 @@ class Profile_list extends Managed_DataObject
* @return boolean success * @return boolean success
*/ */
function delete($useWhere=false) public function delete($useWhere = false)
{ {
// force delete one item at a time. // force delete one item at a time.
if (empty($this->id)) { if (empty($this->id)) {
@ -350,7 +357,7 @@ class Profile_list extends Managed_DataObject
* @return boolean success * @return boolean success
*/ */
function update($dataObject=false) public function update($dataObject = false)
{ {
if (!is_object($dataObject) && !$dataObject instanceof Profile_list) { if (!is_object($dataObject) && !$dataObject instanceof Profile_list) {
return parent::update($dataObject); return parent::update($dataObject);
@ -382,7 +389,7 @@ class Profile_list extends Managed_DataObject
* @return string atom author element * @return string atom author element
*/ */
function asAtomAuthor() public function asAtomAuthor()
{ {
$xs = new XMLStringer(true); $xs = new XMLStringer(true);
@ -404,7 +411,7 @@ class Profile_list extends Managed_DataObject
* @return string activitystreams noun * @return string activitystreams noun
*/ */
function asActivityNoun($element) public function asActivityNoun($element)
{ {
$noun = ActivityObject::fromPeopletag($this); $noun = ActivityObject::fromPeopletag($this);
return $noun->asString('activity:' . $element); return $noun->asString('activity:' . $element);
@ -419,11 +426,13 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
function taggedCount($recount=false) public function taggedCount($recount = false)
{ {
$keypart = sprintf('profile_list:tagged_count:%d:%s', $keypart = sprintf(
'profile_list:tagged_count:%d:%s',
$this->tagger, $this->tagger,
$this->tag); $this->tag
);
$count = self::cacheGet($keypart); $count = self::cacheGet($keypart);
@ -450,15 +459,16 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
function subscriberCount($recount=false) public function subscriberCount($recount = false)
{ {
$keypart = sprintf('profile_list:subscriber_count:%d', $keypart = sprintf(
$this->id); 'profile_list:subscriber_count:%d',
$this->id
);
$count = self::cacheGet($keypart); $count = self::cacheGet($keypart);
if ($count === false) { if ($count === false) {
$sub = new Profile_tag_subscription(); $sub = new Profile_tag_subscription();
$sub->profile_tag_id = $this->id; $sub->profile_tag_id = $this->id;
$count = (int) $sub->count('distinct profile_id'); $count = (int) $sub->count('distinct profile_id');
@ -478,7 +488,7 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
function blowNoticeStreamCache($all=false) public function blowNoticeStreamCache($all = false)
{ {
self::blow('profile_list:notice_ids:%d', $this->id); self::blow('profile_list:notice_ids:%d', $this->id);
if ($all) { if ($all) {
@ -496,7 +506,7 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
static function getByTaggerAndTag($tagger, $tag) public static function getByTaggerAndTag($tagger, $tag)
{ {
$ptag = Profile_list::pkeyGet(array('tagger' => $tagger, 'tag' => $tag)); $ptag = Profile_list::pkeyGet(array('tagger' => $tagger, 'tag' => $tag));
return $ptag; return $ptag;
@ -514,7 +524,7 @@ class Profile_list extends Managed_DataObject
* @return Profile_list the people tag object * @return Profile_list the people tag object
*/ */
static function ensureTag($tagger, $tag, $description=null, $private=false) public static function ensureTag($tagger, $tag, $description = null, $private = false)
{ {
$ptag = Profile_list::getByTaggerAndTag($tagger, $tag); $ptag = Profile_list::getByTaggerAndTag($tagger, $tag);
@ -544,7 +554,7 @@ class Profile_list extends Managed_DataObject
* @return integer maximum number of characters * @return integer maximum number of characters
*/ */
static function maxDescription() public static function maxDescription()
{ {
$desclimit = common_config('peopletag', 'desclimit'); $desclimit = common_config('peopletag', 'desclimit');
// null => use global limit (distinct from 0!) // null => use global limit (distinct from 0!)
@ -563,7 +573,7 @@ class Profile_list extends Managed_DataObject
* @return boolean is the descripition too long? * @return boolean is the descripition too long?
*/ */
static function descriptionTooLong($desc) public static function descriptionTooLong($desc)
{ {
$desclimit = self::maxDescription(); $desclimit = self::maxDescription();
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit)); return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
@ -578,7 +588,8 @@ class Profile_list extends Managed_DataObject
* *
* @return mixed Profile_list on success, false on fail * @return mixed Profile_list on success, false on fail
*/ */
static function saveNew(array $fields) { public static function saveNew(array $fields)
{
extract($fields); extract($fields);
$ptag = new Profile_list(); $ptag = new Profile_list();
@ -687,9 +698,9 @@ class Profile_list extends Managed_DataObject
* @returns array (array (mixed items), int next_cursor, int previous_cursor) * @returns array (array (mixed items), int next_cursor, int previous_cursor)
*/ */
// XXX: This should be in Memcached_DataObject... eventually. // XXX: This should be in Memcached_DataObject... eventually
static function getAtCursor($fn, array $args, $cursor, $count=20) public static function getAtCursor($fn, array $args, $cursor, $count = 20)
{ {
$items = array(); $items = array();
@ -734,7 +745,6 @@ class Profile_list extends Managed_DataObject
$next_cursor = isset($next->cursor) ? $next_cursor = isset($next->cursor) ?
$items[$count-1]->cursor : $items[$count-1]->id; $items[$count-1]->cursor : $items[$count-1]->id;
} }
} elseif ($cursor < -1) { } elseif ($cursor < -1) {
// if cursor is -ve fetch $count+2 items created after -$cursor-1 // if cursor is -ve fetch $count+2 items created after -$cursor-1
$cursor = abs($cursor); $cursor = abs($cursor);
@ -755,7 +765,10 @@ class Profile_list extends Managed_DataObject
} else { } else {
$next_cursor = isset($items[$end]->cursor) ? $next_cursor = isset($items[$end]->cursor) ?
$items[$end]->cursor : $items[$end]->id; $items[$end]->cursor : $items[$end]->id;
if ($end > $count) array_pop($items); // excess item. if ($end > $count) {
// excess item
array_pop($items);
}
// check if there are more items for next page // check if there are more items for next page
$fn_args = array_merge($args, array(0, 1, 0, $cursor)); $fn_args = array_merge($args, array(0, 1, 0, $cursor));
@ -787,7 +800,6 @@ class Profile_list extends Managed_DataObject
$next_cursor = $items[$count-1]->id; $next_cursor = $items[$count-1]->id;
} }
} }
} }
return array($items, $next_cursor, $prev_cursor); return array($items, $next_cursor, $prev_cursor);
} }
@ -803,7 +815,8 @@ class Profile_list extends Managed_DataObject
* @return boolean success * @return boolean success
*/ */
static function setCache($ckey, &$tag, $offset=0, $limit=null) { public static function setCache($ckey, &$tag, $offset = 0, $limit = null)
{
$cache = Cache::instance(); $cache = Cache::instance();
if (empty($cache)) { if (empty($cache)) {
return false; return false;
@ -834,8 +847,8 @@ class Profile_list extends Managed_DataObject
* @return Profile_list results * @return Profile_list results
*/ */
static function getCached($ckey, $offset=0, $limit=null) { public static function getCached($ckey, $offset = 0, $limit = null)
{
$keys_str = self::cacheGet($ckey); $keys_str = self::cacheGet($ckey);
if ($keys_str === false) { if ($keys_str === false) {
return false; return false;
@ -862,7 +875,8 @@ class Profile_list extends Managed_DataObject
* @return Profile_list results * @return Profile_list results
*/ */
static function getByKeys(array $keys) { public static function getByKeys(array $keys)
{
$cache = Cache::instance(); $cache = Cache::instance();
if (!empty($cache)) { if (!empty($cache)) {
@ -910,7 +924,7 @@ class Profile_list extends Managed_DataObject
} }
} }
function insert() public function insert()
{ {
$result = parent::insert(); $result = parent::insert();
if ($result) { if ($result) {

View File

@ -1,23 +1,20 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
* GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License
* // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for user * Table Definition for user
@ -144,7 +141,7 @@ class User extends Managed_DataObject
return $this->getProfile()->getNickname(); return $this->getProfile()->getNickname();
} }
static function getByNickname($nickname) public static function getByNickname($nickname)
{ {
$user = User::getKV('nickname', $nickname); $user = User::getKV('nickname', $nickname);
if (!$user instanceof User) { if (!$user instanceof User) {
@ -154,12 +151,12 @@ class User extends Managed_DataObject
return $user; return $user;
} }
function isSubscribed(Profile $other) public function isSubscribed(Profile $other)
{ {
return $this->getProfile()->isSubscribed($other); return $this->getProfile()->isSubscribed($other);
} }
function hasPendingSubscription(Profile $other) public function hasPendingSubscription(Profile $other)
{ {
return $this->getProfile()->hasPendingSubscription($other); return $this->getProfile()->hasPendingSubscription($other);
} }
@ -169,17 +166,17 @@ class User extends Managed_DataObject
* *
* @return mixed Notice or null * @return mixed Notice or null
*/ */
function getCurrentNotice() public function getCurrentNotice()
{ {
return $this->getProfile()->getCurrentNotice(); return $this->getProfile()->getCurrentNotice();
} }
function getCarrier() public function getCarrier()
{ {
return Sms_carrier::getKV('id', $this->carrier); return Sms_carrier::getKV('id', $this->carrier);
} }
function hasBlocked(Profile $other) public function hasBlocked(Profile $other)
{ {
return $this->getProfile()->hasBlocked($other); return $this->getProfile()->hasBlocked($other);
} }
@ -206,10 +203,9 @@ class User extends Managed_DataObject
* @return User object * @return User object
* @throws Exception on failure * @throws Exception on failure
*/ */
static function register(array $fields, $accept_email_fail=false) { public static function register(array $fields, $accept_email_fail = false)
{
// MAGICALLY put fields into current scope // MAGICALLY put fields into current scope
extract($fields); extract($fields);
$profile = new Profile(); $profile = new Profile();
@ -278,7 +274,6 @@ class User extends Managed_DataObject
$user->created = common_sql_now(); $user->created = common_sql_now();
if (Event::handle('StartUserRegister', array($profile))) { if (Event::handle('StartUserRegister', array($profile))) {
$profile->query('BEGIN'); $profile->query('BEGIN');
$id = $profile->insert(); $id = $profile->insert();
@ -367,8 +362,11 @@ class User extends Managed_DataObject
if (!empty($defnick)) { if (!empty($defnick)) {
$defuser = User::getKV('nickname', $defnick); $defuser = User::getKV('nickname', $defnick);
if (empty($defuser)) { if (empty($defuser)) {
common_log(LOG_WARNING, sprintf("Default user %s does not exist.", $defnick), common_log(
__FILE__); LOG_WARNING,
sprintf('Default user %s does not exist.', $defnick),
__FILE__
);
} else { } else {
Subscription::ensureStart($profile, $defuser->getProfile()); Subscription::ensureStart($profile, $defuser->getProfile());
} }
@ -394,16 +392,23 @@ class User extends Managed_DataObject
if (!empty($welcome)) { if (!empty($welcome)) {
$welcomeuser = User::getKV('nickname', $welcome); $welcomeuser = User::getKV('nickname', $welcome);
if (empty($welcomeuser)) { if (empty($welcomeuser)) {
common_log(LOG_WARNING, sprintf("Welcome user %s does not exist.", $defnick), common_log(
__FILE__); LOG_WARNING,
sprintf('Welcome user %s does not exist.', $defnick),
__FILE__
);
} else { } else {
$notice = Notice::saveNew($welcomeuser->id, $notice = Notice::saveNew(
$welcomeuser->id,
// TRANS: Notice given on user registration. // TRANS: Notice given on user registration.
// TRANS: %1$s is the sitename, $2$s is the registering user's nickname. // TRANS: %1$s is the sitename, $2$s is the registering user's nickname.
sprintf(_('Welcome to %1$s, @%2$s!'), sprintf(
_('Welcome to %1$s, @%2$s!'),
common_config('site', 'name'), common_config('site', 'name'),
$profile->getNickname()), $profile->getNickname()
'system'); ),
'system'
);
} }
} }
@ -418,9 +423,8 @@ class User extends Managed_DataObject
} }
// Things we do when the email changes // Things we do when the email changes
function emailChanged() public function emailChanged()
{ {
$invites = new Invitation(); $invites = new Invitation();
$invites->address = $this->email; $invites->address = $this->email;
$invites->address_type = 'email'; $invites->address_type = 'email';
@ -441,48 +445,53 @@ class User extends Managed_DataObject
} }
} }
function mutuallySubscribed(Profile $other) public function mutuallySubscribed(Profile $other)
{ {
return $this->getProfile()->mutuallySubscribed($other); return $this->getProfile()->mutuallySubscribed($other);
} }
function mutuallySubscribedUsers() public function mutuallySubscribedUsers()
{ {
// 3-way join; probably should get cached
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$qry = "SELECT $UT.* " .
"FROM subscription sub1 JOIN $UT ON sub1.subscribed = $UT.id " .
"JOIN subscription sub2 ON $UT.id = sub2.subscriber " .
'WHERE sub1.subscriber = %d and sub2.subscribed = %d ' .
"ORDER BY $UT.nickname";
$user = new User(); $user = new User();
$user->query(sprintf($qry, $this->id, $this->id));
// 3-way join; probably should get cached
$user->query(sprintf(
'SELECT %1$s.* ' .
'FROM subscription AS sub1 INNER JOIN %1$s ON sub1.subscribed = %1$s.id ' .
'INNER JOIN subscription AS sub2 ON %1$s.id = sub2.subscriber ' .
'WHERE sub1.subscriber = %2$d AND sub2.subscribed = %2$d ' .
'ORDER BY %1$s.nickname',
$user->escapedTableName(),
$this->id
));
return $user; return $user;
} }
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) public function getReplies($offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $before_id = 0)
{ {
return $this->getProfile()->getReplies($offset, $limit, $since_id, $before_id); return $this->getProfile()->getReplies($offset, $limit, $since_id, $before_id);
} }
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) { public function getTaggedNotices($tag, $offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $before_id = 0)
{
return $this->getProfile()->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id); return $this->getProfile()->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id);
} }
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) public function getNotices($offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $before_id = 0)
{ {
return $this->getProfile()->getNotices($offset, $limit, $since_id, $before_id); return $this->getProfile()->getNotices($offset, $limit, $since_id, $before_id);
} }
function block(Profile $other) public function block(Profile $other)
{ {
// Add a new block record // Add a new block record
// no blocking (and thus unsubbing from) yourself // no blocking (and thus unsubbing from) yourself
if ($this->id == $other->id) { if ($this->id == $other->id) {
common_log(LOG_WARNING, common_log(
LOG_WARNING,
sprintf( sprintf(
"Profile ID %d (%s) tried to block themself.", "Profile ID %d (%s) tried to block themself.",
$this->id, $this->id,
@ -521,7 +530,7 @@ class User extends Managed_DataObject
return true; return true;
} }
function unblock(Profile $other) public function unblock(Profile $other)
{ {
// Get the block record // Get the block record
@ -541,17 +550,17 @@ class User extends Managed_DataObject
return true; return true;
} }
function isMember(User_group $group) public function isMember(User_group $group)
{ {
return $this->getProfile()->isMember($group); return $this->getProfile()->isMember($group);
} }
function isAdmin(User_group $group) public function isAdmin(User_group $group)
{ {
return $this->getProfile()->isAdmin($group); return $this->getProfile()->isAdmin($group);
} }
function getGroups($offset=0, $limit=null) public function getGroups($offset = 0, $limit = null)
{ {
return $this->getProfile()->getGroups($offset, $limit); return $this->getProfile()->getGroups($offset, $limit);
} }
@ -563,7 +572,7 @@ class User extends Managed_DataObject
* @param User_group $group * @param User_group $group
* @return Group_member * @return Group_member
*/ */
function joinGroup(User_group $group) public function joinGroup(User_group $group)
{ {
return $this->getProfile()->joinGroup($group); return $this->getProfile()->joinGroup($group);
} }
@ -573,37 +582,37 @@ class User extends Managed_DataObject
* *
* @param User_group $group * @param User_group $group
*/ */
function leaveGroup(User_group $group) public function leaveGroup(User_group $group)
{ {
return $this->getProfile()->leaveGroup($group); return $this->getProfile()->leaveGroup($group);
} }
function getSubscribed($offset=0, $limit=null) public function getSubscribed($offset = 0, $limit = null)
{ {
return $this->getProfile()->getSubscribed($offset, $limit); return $this->getProfile()->getSubscribed($offset, $limit);
} }
function getSubscribers($offset=0, $limit=null) public function getSubscribers($offset = 0, $limit = null)
{ {
return $this->getProfile()->getSubscribers($offset, $limit); return $this->getProfile()->getSubscribers($offset, $limit);
} }
function getTaggedSubscribers($tag, $offset=0, $limit=null) public function getTaggedSubscribers($tag, $offset = 0, $limit = null)
{ {
return $this->getProfile()->getTaggedSubscribers($tag, $offset, $limit); return $this->getProfile()->getTaggedSubscribers($tag, $offset, $limit);
} }
function getTaggedSubscriptions($tag, $offset=0, $limit=null) public function getTaggedSubscriptions($tag, $offset = 0, $limit = null)
{ {
return $this->getProfile()->getTaggedSubscriptions($tag, $offset, $limit); return $this->getProfile()->getTaggedSubscriptions($tag, $offset, $limit);
} }
function hasRight($right) public function hasRight($right)
{ {
return $this->getProfile()->hasRight($right); return $this->getProfile()->hasRight($right);
} }
function delete($useWhere=false) public function delete($useWhere = false)
{ {
if (empty($this->id)) { if (empty($this->id)) {
common_log(LOG_WARNING, "Ambiguous User->delete(); skipping related tables."); common_log(LOG_WARNING, "Ambiguous User->delete(); skipping related tables.");
@ -640,14 +649,14 @@ class User extends Managed_DataObject
return parent::delete($useWhere); return parent::delete($useWhere);
} }
function _deleteTags() public function _deleteTags()
{ {
$tag = new Profile_tag(); $tag = new Profile_tag();
$tag->tagger = $this->id; $tag->tagger = $this->id;
$tag->delete(); $tag->delete();
} }
function _deleteBlocks() public function _deleteBlocks()
{ {
$block = new Profile_block(); $block = new Profile_block();
$block->blocker = $this->id; $block->blocker = $this->id;
@ -655,32 +664,32 @@ class User extends Managed_DataObject
// XXX delete group block? Reset blocker? // XXX delete group block? Reset blocker?
} }
function hasRole($name) public function hasRole($name)
{ {
return $this->getProfile()->hasRole($name); return $this->getProfile()->hasRole($name);
} }
function grantRole($name) public function grantRole($name)
{ {
return $this->getProfile()->grantRole($name); return $this->getProfile()->grantRole($name);
} }
function revokeRole($name) public function revokeRole($name)
{ {
return $this->getProfile()->revokeRole($name); return $this->getProfile()->revokeRole($name);
} }
function isSandboxed() public function isSandboxed()
{ {
return $this->getProfile()->isSandboxed(); return $this->getProfile()->isSandboxed();
} }
function isSilenced() public function isSilenced()
{ {
return $this->getProfile()->isSilenced(); return $this->getProfile()->isSilenced();
} }
function receivesEmailNotifications() public function receivesEmailNotifications()
{ {
// We could do this in one large if statement, but that's not as easy to read // We could do this in one large if statement, but that's not as easy to read
// Don't send notifications if we don't know the user's email address or it is // Don't send notifications if we don't know the user's email address or it is
@ -695,7 +704,7 @@ class User extends Managed_DataObject
return true; return true;
} }
function repeatedByMe($offset=0, $limit=20, $since_id=null, $max_id=null) public function repeatedByMe($offset = 0, $limit = 20, $since_id = null, $max_id = null)
{ {
// FIXME: Use another way to get Profile::current() since we // FIXME: Use another way to get Profile::current() since we
// want to avoid confusion between session user and queue processing. // want to avoid confusion between session user and queue processing.
@ -704,7 +713,7 @@ class User extends Managed_DataObject
} }
function repeatsOfMe($offset=0, $limit=20, $since_id=null, $max_id=null) public function repeatsOfMe($offset = 0, $limit = 20, $since_id = null, $max_id = null)
{ {
// FIXME: Use another way to get Profile::current() since we // FIXME: Use another way to get Profile::current() since we
// want to avoid confusion between session user and queue processing. // want to avoid confusion between session user and queue processing.
@ -791,7 +800,7 @@ class User extends Managed_DataObject
* @throws ServerException if no valid single user account is present * @throws ServerException if no valid single user account is present
* @throws ServerException if called when not in single-user mode * @throws ServerException if called when not in single-user mode
*/ */
static function singleUserNickname() public static function singleUserNickname()
{ {
try { try {
$user = User::singleUser(); $user = User::singleUser();
@ -828,7 +837,7 @@ class User extends Managed_DataObject
* Get a list of OAuth client applications that have access to this * Get a list of OAuth client applications that have access to this
* user's account. * user's account.
*/ */
function getConnectedApps($offset = 0, $limit = null) public function getConnectedApps($offset = 0, $limit = null)
{ {
$qry = $qry =
'SELECT u.* ' . 'SELECT u.* ' .
@ -863,14 +872,14 @@ class User extends Managed_DataObject
* @return array of variable names to include in serialization. * @return array of variable names to include in serialization.
*/ */
function __sleep() public function __sleep()
{ {
$vars = parent::__sleep(); $vars = parent::__sleep();
$skip = array('_profile'); $skip = array('_profile');
return array_diff($vars, $skip); return array_diff($vars, $skip);
} }
static function recoverPassword($nore) public static function recoverPassword($nore)
{ {
require_once INSTALLDIR . '/lib/util/mail.php'; require_once INSTALLDIR . '/lib/util/mail.php';
@ -951,8 +960,10 @@ class User extends Managed_DataObject
$body .= "\n\n"; $body .= "\n\n";
$body .= 'If it was you, and you want to confirm, use the URL below:'; $body .= 'If it was you, and you want to confirm, use the URL below:';
$body .= "\n\n"; $body .= "\n\n";
$body .= "\t".common_local_url('recoverpassword', $body .= "\t" . common_local_url(
array('code' => $confirm->code)); 'recoverpassword',
['code' => $confirm->code]
);
$body .= "\n\n"; $body .= "\n\n";
$body .= 'If not, just ignore this message.'; $body .= 'If not, just ignore this message.';
$body .= "\n\n"; $body .= "\n\n";
@ -966,7 +977,7 @@ class User extends Managed_DataObject
mail_to_user($user, _('Password recovery requested'), $body, $headers, $confirm->address); mail_to_user($user, _('Password recovery requested'), $body, $headers, $confirm->address);
} }
function streamModeOnly() public function streamModeOnly()
{ {
if (common_config('oldschool', 'enabled')) { if (common_config('oldschool', 'enabled')) {
$osp = Old_school_prefs::getKV('user_id', $this->id); $osp = Old_school_prefs::getKV('user_id', $this->id);
@ -978,7 +989,7 @@ class User extends Managed_DataObject
return false; return false;
} }
function streamNicknames() public function streamNicknames()
{ {
if (common_config('oldschool', 'enabled')) { if (common_config('oldschool', 'enabled')) {
$osp = Old_school_prefs::getKV('user_id', $this->id); $osp = Old_school_prefs::getKV('user_id', $this->id);
@ -989,7 +1000,7 @@ class User extends Managed_DataObject
return false; return false;
} }
function registrationActivity() public function registrationActivity()
{ {
$profile = $this->getProfile(); $profile = $this->getProfile();
@ -1007,16 +1018,20 @@ class User extends Managed_DataObject
$act->objects[] = $service; $act->objects[] = $service;
$act->id = TagURI::mint('user:register:%d', $act->id = TagURI::mint(
$this->id); 'user:register:%d',
$this->id
);
$act->time = strtotime($this->created); $act->time = strtotime($this->created);
$act->title = _("Register"); $act->title = _("Register");
$act->content = sprintf(_('%1$s joined %2$s.'), $act->content = sprintf(
_('%1$s joined %2$s.'),
$profile->getBestName(), $profile->getBestName(),
$service->title); $service->title
);
return $act; return $act;
} }

View File

@ -1,8 +1,24 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
/** /**
* Table Definition for user_group * Table Definition for user_group
*/ */
class User_group extends Managed_DataObject class User_group extends Managed_DataObject
{ {
const JOIN_POLICY_OPEN = 0; const JOIN_POLICY_OPEN = 0;
@ -118,40 +134,38 @@ class User_group extends Managed_DataObject
return Theme::path('default-avatar-'.$sizenames[$size].'.png'); return Theme::path('default-avatar-'.$sizenames[$size].'.png');
} }
function homeUrl() public function homeUrl()
{ {
return $this->getProfile()->getUrl(); return $this->getProfile()->getUrl();
} }
function getUri() public function getUri()
{ {
$uri = null; $uri = null;
if (Event::handle('StartUserGroupGetUri', array($this, &$uri))) { if (Event::handle('StartUserGroupGetUri', array($this, &$uri))) {
if (!empty($this->uri)) { if (!empty($this->uri)) {
$uri = $this->uri; $uri = $this->uri;
} elseif ($this->isLocal()) { } elseif ($this->isLocal()) {
$uri = common_local_url('groupbyid', $uri = common_local_url('groupbyid', ['id' => $this->id]);
array('id' => $this->id));
} }
} }
Event::handle('EndUserGroupGetUri', array($this, &$uri)); Event::handle('EndUserGroupGetUri', array($this, &$uri));
return $uri; return $uri;
} }
function permalink() public function permalink()
{ {
$url = null; $url = null;
if (Event::handle('StartUserGroupPermalink', array($this, &$url))) { if (Event::handle('StartUserGroupPermalink', array($this, &$url))) {
if ($this->isLocal()) { if ($this->isLocal()) {
$url = common_local_url('groupbyid', $url = common_local_url('groupbyid', ['id' => $this->id]);
array('id' => $this->id));
} }
} }
Event::handle('EndUserGroupPermalink', array($this, &$url)); Event::handle('EndUserGroupPermalink', array($this, &$url));
return $url; return $url;
} }
function getNotices($offset, $limit, $since_id=null, $max_id=null) public function getNotices($offset, $limit, $since_id = null, $max_id = null)
{ {
// FIXME: Get the Profile::current() some other way, to avoid // FIXME: Get the Profile::current() some other way, to avoid
// possible confusion between current session and queue process. // possible confusion between current session and queue process.
@ -160,29 +174,26 @@ class User_group extends Managed_DataObject
return $stream->getNotices($offset, $limit, $since_id, $max_id); return $stream->getNotices($offset, $limit, $since_id, $max_id);
} }
function getMembers($offset=0, $limit=null) { public function getMembers($offset = 0, $limit = null)
{
$ids = null; $ids = null;
if (is_null($limit) || $offset + $limit > User_group::CACHE_WINDOW) { if (is_null($limit) || $offset + $limit > User_group::CACHE_WINDOW) {
$ids = $this->getMemberIDs($offset, $ids = $this->getMemberIDs($offset, $limit);
$limit);
} else { } else {
$key = sprintf('group:member_ids:%d', $this->id); $key = sprintf('group:member_ids:%d', $this->id);
$window = self::cacheGet($key); $window = self::cacheGet($key);
if ($window === false) { if ($window === false) {
$window = $this->getMemberIDs(0, $window = $this->getMemberIDs(0, User_group::CACHE_WINDOW);
User_group::CACHE_WINDOW);
self::cacheSet($key, $window); self::cacheSet($key, $window);
} }
$ids = array_slice($window, $ids = array_slice($window, $offset, $limit);
$offset,
$limit);
} }
return Profile::multiGet('id', $ids); return Profile::multiGet('id', $ids);
} }
function getMemberIDs($offset=0, $limit=null) public function getMemberIDs($offset = 0, $limit = null)
{ {
$gm = new Group_member(); $gm = new Group_member();
@ -215,7 +226,7 @@ class User_group extends Managed_DataObject
* @param int $limit * @param int $limit
* @return Profile * @return Profile
*/ */
function getRequests($offset=0, $limit=null) public function getRequests($offset = 0, $limit = null)
{ {
$rq = new Group_join_queue(); $rq = new Group_join_queue();
$rq->group_id = $this->id; $rq->group_id = $this->id;
@ -264,7 +275,7 @@ class User_group extends Managed_DataObject
return $cnt; return $cnt;
} }
function getBlockedCount() public function getBlockedCount()
{ {
// XXX: WORM cache this // XXX: WORM cache this
@ -274,7 +285,7 @@ class User_group extends Managed_DataObject
return $block->count(); return $block->count();
} }
function getQueueCount() public function getQueueCount()
{ {
// XXX: WORM cache this // XXX: WORM cache this
@ -284,7 +295,8 @@ class User_group extends Managed_DataObject
return $queue->count(); return $queue->count();
} }
function getAdmins($offset=null, $limit=null) // offset is null because DataObject wants it, 0 would mean no results // offset is null because DataObject wants it, 0 would mean no results
public function getAdmins($offset = null, $limit = null)
{ {
$admins = new Profile(); $admins = new Profile();
$admins->joinAdd(array('id', 'group_member:profile_id')); $admins->joinAdd(array('id', 'group_member:profile_id'));
@ -296,7 +308,8 @@ class User_group extends Managed_DataObject
return $admins; return $admins;
} }
function getBlocked($offset=null, $limit=null) // offset is null because DataObject wants it, 0 would mean no results // offset is null because DataObject wants it, 0 would mean no results
public function getBlocked($offset = null, $limit = null)
{ {
$blocked = new Profile(); $blocked = new Profile();
$blocked->joinAdd(array('id', 'group_block:blocked')); $blocked->joinAdd(array('id', 'group_block:blocked'));
@ -308,7 +321,7 @@ class User_group extends Managed_DataObject
return $blocked; return $blocked;
} }
function setOriginal($filename) public function setOriginal($filename)
{ {
// This should be handled by the Profile->setOriginal function so user and group avatars are handled the same // This should be handled by the Profile->setOriginal function so user and group avatars are handled the same
$imagefile = new ImageFile(null, Avatar::path($filename)); $imagefile = new ImageFile(null, Avatar::path($filename));
@ -320,8 +333,12 @@ class User_group extends Managed_DataObject
$orig = clone($this); $orig = clone($this);
$this->original_logo = Avatar::url($filename); $this->original_logo = Avatar::url($filename);
foreach ($sizes as $name=>$size) { foreach ($sizes as $name=>$size) {
$filename = Avatar::filename($this->profile_id, image_type_to_extension($imagefile->preferredType()), $filename = Avatar::filename(
$size, common_timestamp()); $this->profile_id,
image_type_to_extension($imagefile->preferredType()),
$size,
common_timestamp()
);
$imagefile->resizeTo(Avatar::path($filename), array('width'=>$size, 'height'=>$size)); $imagefile->resizeTo(Avatar::path($filename), array('width'=>$size, 'height'=>$size));
$this->$name = Avatar::url($filename); $this->$name = Avatar::url($filename);
} }
@ -329,7 +346,7 @@ class User_group extends Managed_DataObject
return $this->update($orig); return $this->update($orig);
} }
function getBestName() public function getBestName()
{ {
return ($this->fullname) ? $this->fullname : $this->nickname; return ($this->fullname) ? $this->fullname : $this->nickname;
} }
@ -340,7 +357,7 @@ class User_group extends Managed_DataObject
* *
* @return string * @return string
*/ */
function getFancyName() public function getFancyName()
{ {
if ($this->fullname) { if ($this->fullname) {
// TRANS: Full name of a profile or group followed by nickname in parens // TRANS: Full name of a profile or group followed by nickname in parens
@ -350,7 +367,7 @@ class User_group extends Managed_DataObject
} }
} }
function getAliases() public function getAliases()
{ {
$aliases = array(); $aliases = array();
@ -371,8 +388,8 @@ class User_group extends Managed_DataObject
return $aliases; return $aliases;
} }
function setAliases($newaliases) { public function setAliases($newaliases)
{
$newaliases = array_unique($newaliases); $newaliases = array_unique($newaliases);
$oldaliases = $this->getAliases(); $oldaliases = $this->getAliases();
@ -413,7 +430,7 @@ class User_group extends Managed_DataObject
return true; return true;
} }
static function getForNickname($nickname, Profile $profile=null) public static function getForNickname($nickname, Profile $profile = null)
{ {
$nickname = Nickname::normalize($nickname); $nickname = Nickname::normalize($nickname);
@ -440,24 +457,21 @@ class User_group extends Managed_DataObject
return null; return null;
} }
function getUserMembers() public function getUserMembers()
{ {
// XXX: cache this // XXX: cache this
$user = new User(); $user = new User();
if(common_config('db','quote_identifiers'))
$user_table = '"user"';
else $user_table = 'user';
$qry = $user->query(sprintf(
'SELECT id ' . 'SELECT id FROM %1$s INNER JOIN group_member ' .
'FROM '. $user_table .' JOIN group_member '. 'ON %1$s.id = group_member.profile_id ' .
'ON '. $user_table .'.id = group_member.profile_id ' . 'WHERE group_member.group_id = %2$d ',
'WHERE group_member.group_id = %d '; $user->escapedTableName(),
$this->id
));
$user->query(sprintf($qry, $this->id)); $ids = [];
$ids = array();
while ($user->fetch()) { while ($user->fetch()) {
$ids[] = $user->id; $ids[] = $user->id;
@ -468,7 +482,7 @@ class User_group extends Managed_DataObject
return $ids; return $ids;
} }
static function maxDescription() public static function maxDescription()
{ {
$desclimit = common_config('group', 'desclimit'); $desclimit = common_config('group', 'desclimit');
// null => use global limit (distinct from 0!) // null => use global limit (distinct from 0!)
@ -478,13 +492,13 @@ class User_group extends Managed_DataObject
return $desclimit; return $desclimit;
} }
static function descriptionTooLong($desc) public static function descriptionTooLong($desc)
{ {
$desclimit = self::maxDescription(); $desclimit = self::maxDescription();
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit)); return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
} }
function asAtomEntry($namespace=false, $source=false) public function asAtomEntry($namespace = false, $source = false)
{ {
$xs = new XMLStringer(true); $xs = new XMLStringer(true);
@ -528,7 +542,7 @@ class User_group extends Managed_DataObject
return $xs->getString(); return $xs->getString();
} }
function asAtomAuthor() public function asAtomAuthor()
{ {
$xs = new XMLStringer(true); $xs = new XMLStringer(true);
@ -551,20 +565,21 @@ class User_group extends Managed_DataObject
* *
* @return string * @return string
*/ */
function asActivityNoun($element) public function asActivityNoun($element)
{ {
$noun = ActivityObject::fromGroup($this); $noun = ActivityObject::fromGroup($this);
return $noun->asString('activity:' . $element); return $noun->asString('activity:' . $element);
} }
function getAvatar() public function getAvatar()
{ {
return empty($this->homepage_logo) return empty($this->homepage_logo)
? User_group::defaultLogo(AVATAR_PROFILE_SIZE) ? User_group::defaultLogo(AVATAR_PROFILE_SIZE)
: $this->homepage_logo; : $this->homepage_logo;
} }
static function register($fields) { public static function register($fields)
{
if (!empty($fields['userid'])) { if (!empty($fields['userid'])) {
$profile = Profile::getKV('id', $fields['userid']); $profile = Profile::getKV('id', $fields['userid']);
if ($profile && !$profile->hasRight(Right::CREATEGROUP)) { if ($profile && !$profile->hasRight(Right::CREATEGROUP)) {
@ -580,15 +595,17 @@ class User_group extends Managed_DataObject
// MAGICALLY put fields into current scope // MAGICALLY put fields into current scope
// @fixme kill extract(); it makes debugging absurdly hard // @fixme kill extract(); it makes debugging absurdly hard
$defaults = array('nickname' => null, $defaults = [
'nickname' => null,
'fullname' => null, 'fullname' => null,
'homepage' => null, 'homepage' => null,
'description' => null, 'description' => null,
'location' => null, 'location' => null,
'uri' => null, 'uri' => null,
'mainpage' => null, 'mainpage' => null,
'aliases' => array(), 'aliases' => [],
'userid' => null); 'userid' => null,
];
$fields = array_merge($defaults, $fields); $fields = array_merge($defaults, $fields);
@ -645,7 +662,6 @@ class User_group extends Managed_DataObject
} }
if (Event::handle('StartGroupSave', array(&$group))) { if (Event::handle('StartGroupSave', array(&$group))) {
$result = $group->insert(); $result = $group->insert();
if ($result === false) { if ($result === false) {
@ -721,7 +737,7 @@ class User_group extends Managed_DataObject
* are not de-cached in the UI, including the sidebar lists on * are not de-cached in the UI, including the sidebar lists on
* GroupsAction * GroupsAction
*/ */
function delete($useWhere=false) public function delete($useWhere = false)
{ {
if (empty($this->id)) { if (empty($this->id)) {
common_log(LOG_WARNING, "Ambiguous User_group->delete(); skipping related tables."); common_log(LOG_WARNING, "Ambiguous User_group->delete(); skipping related tables.");
@ -813,7 +829,7 @@ class User_group extends Managed_DataObject
return parent::update($dataObject); return parent::update($dataObject);
} }
function isPrivate() public function isPrivate()
{ {
return ($this->join_policy == self::JOIN_POLICY_MODERATE && return ($this->join_policy == self::JOIN_POLICY_MODERATE &&
intval($this->force_scope) === 1); intval($this->force_scope) === 1);
@ -825,14 +841,16 @@ class User_group extends Managed_DataObject
return ($local instanceof Local_group); return ($local instanceof Local_group);
} }
static function groupsFromText($text, Profile $profile) public static function groupsFromText($text, Profile $profile)
{ {
$groups = array(); $groups = array();
/* extract all !group */ /* extract all !group */
$count = preg_match_all('/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/', $count = preg_match_all(
'/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/',
strtolower($text), strtolower($text),
$match); $match
);
if (!$count) { if (!$count) {
return $groups; return $groups;
@ -848,7 +866,7 @@ class User_group extends Managed_DataObject
return $groups; return $groups;
} }
static function idsFromText($text, Profile $profile) public static function idsFromText($text, Profile $profile)
{ {
$ids = array(); $ids = array();
$groups = self::groupsFromText($text, $profile); $groups = self::groupsFromText($text, $profile);

View File

@ -52,7 +52,6 @@ class PgsqlSchema extends Schema
* @return array tabledef for that table. * @return array tabledef for that table.
* @throws SchemaTableMissingException * @throws SchemaTableMissingException
*/ */
public function getTableDef($table) public function getTableDef($table)
{ {
$def = []; $def = [];
@ -68,7 +67,6 @@ class PgsqlSchema extends Schema
$orderedFields = []; $orderedFields = [];
foreach ($columns as $row) { foreach ($columns as $row) {
$name = $row['column_name']; $name = $row['column_name'];
$orderedFields[$row['ordinal_position']] = $name; $orderedFields[$row['ordinal_position']] = $name;
@ -166,7 +164,7 @@ class PgsqlSchema extends Schema
* @return array of arrays * @return array of arrays
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function fetchMetaInfo($table, $infoTable, $orderBy = null) public function fetchMetaInfo($table, $infoTable, $orderBy = null)
{ {
$query = "SELECT * FROM information_schema.%s " . $query = "SELECT * FROM information_schema.%s " .
"WHERE table_name='%s'"; "WHERE table_name='%s'";
@ -183,7 +181,7 @@ class PgsqlSchema extends Schema
* @return array of arrays * @return array of arrays
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function getIndexInfo($table) public function getIndexInfo($table)
{ {
$query = 'SELECT ' . $query = 'SELECT ' .
'(SELECT relname FROM pg_class WHERE oid=indexrelid) AS key_name, ' . '(SELECT relname FROM pg_class WHERE oid=indexrelid) AS key_name, ' .
@ -202,7 +200,7 @@ class PgsqlSchema extends Schema
* @return array array of rows with keys: fkey_name, table_name, table_id, col_names (array of strings) * @return array array of rows with keys: fkey_name, table_name, table_id, col_names (array of strings)
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function getForeignKeyInfo($table, $constraint_name) public function getForeignKeyInfo($table, $constraint_name)
{ {
// In a sane world, it'd be easier to query the column names directly. // In a sane world, it'd be easier to query the column names directly.
// But it's pretty hard to work with arrays such as col_indexes in direct SQL here. // But it's pretty hard to work with arrays such as col_indexes in direct SQL here.
@ -234,7 +232,7 @@ class PgsqlSchema extends Schema
* @return array of strings * @return array of strings
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function getTableColumnNames($table_id, $col_indexes) public function getTableColumnNames($table_id, $col_indexes)
{ {
$indexes = array_map('intval', explode(' ', $col_indexes)); $indexes = array_map('intval', explode(' ', $col_indexes));
$query = 'SELECT attnum AS col_index, attname AS col_name ' . $query = 'SELECT attnum AS col_index, attname AS col_name ' .
@ -284,7 +282,7 @@ class PgsqlSchema extends Schema
* @return string correct SQL for that column * @return string correct SQL for that column
*/ */
function columnSql(array $cd) public function columnSql(array $cd)
{ {
$line = []; $line = [];
$line[] = parent::columnSql($cd); $line[] = parent::columnSql($cd);
@ -311,7 +309,7 @@ class PgsqlSchema extends Schema
* @param array $old previous column definition as found in DB * @param array $old previous column definition as found in DB
* @param array $cd current column definition * @param array $cd current column definition
*/ */
function appendAlterModifyColumn(array &$phrase, $columnName, array $old, array $cd) public function appendAlterModifyColumn(array &$phrase, $columnName, array $old, array $cd)
{ {
$prefix = 'ALTER COLUMN ' . $this->quoteIdentifier($columnName) . ' '; $prefix = 'ALTER COLUMN ' . $this->quoteIdentifier($columnName) . ' ';
@ -342,23 +340,12 @@ class PgsqlSchema extends Schema
* @param string $table * @param string $table
* @param string $name * @param string $name
*/ */
function appendDropIndex(array &$statements, $table, $name) public function appendDropIndex(array &$statements, $table, $name)
{ {
$statements[] = "DROP INDEX $name"; $statements[] = "DROP INDEX $name";
} }
/** public function mapType($column)
* Quote a db/table/column identifier if necessary.
*
* @param string $name
* @return string
*/
function quoteIdentifier($name)
{
return $this->conn->quoteIdentifier($name);
}
function mapType($column)
{ {
$map = [ $map = [
'serial' => 'bigserial', // FIXME: creates the wrong name for the sequence for some internal sequence-lookup function, so better fix this to do the real 'create sequence' dance. 'serial' => 'bigserial', // FIXME: creates the wrong name for the sequence for some internal sequence-lookup function, so better fix this to do the real 'create sequence' dance.
@ -388,7 +375,7 @@ class PgsqlSchema extends Schema
} }
// @fixme need name... :P // @fixme need name... :P
function typeAndSize($column) public function typeAndSize($column)
{ {
if ($column['type'] == 'enum') { if ($column['type'] == 'enum') {
$vals = array_map([$this, 'quote'], $column['enum']); $vals = array_map([$this, 'quote'], $column['enum']);
@ -408,7 +395,7 @@ class PgsqlSchema extends Schema
* @param array $tableDef * @param array $tableDef
* @return array * @return array
*/ */
function filterDef(array $tableDef) public function filterDef(array $tableDef)
{ {
foreach ($tableDef['fields'] as $name => &$col) { foreach ($tableDef['fields'] as $name => &$col) {
// No convenient support for field descriptions // No convenient support for field descriptions
@ -443,7 +430,7 @@ class PgsqlSchema extends Schema
* @param array $def * @param array $def
* @return array * @return array
*/ */
function filterKeyDef(array $def) public function filterKeyDef(array $def)
{ {
// PostgreSQL doesn't like prefix lengths specified on keys...? // PostgreSQL doesn't like prefix lengths specified on keys...?
foreach ($def as $i => $item) { foreach ($def as $i => $item) {

View File

@ -39,14 +39,13 @@ defined('GNUSOCIAL') || die();
*/ */
class Schema class Schema
{ {
static $_static = null; public static $_static = null;
protected $conn = null; protected $conn = null;
/** /**
* Constructor. Only run once for singleton object. * Constructor. Only run once for singleton object.
* @param null $conn * @param null $conn
*/ */
protected function __construct($conn = null) protected function __construct($conn = null)
{ {
if (is_null($conn)) { if (is_null($conn)) {
@ -64,11 +63,10 @@ class Schema
* Main public entry point. Use this to get * Main public entry point. Use this to get
* the schema object. * the schema object.
* *
* @param null $conn * @param object|null $conn
* @return Schema the Schema object for the connection * @return Schema the Schema object for the connection
*/ */
public static function get($conn = null)
static function get($conn = null)
{ {
if (is_null($conn)) { if (is_null($conn)) {
$key = 'default'; $key = 'default';
@ -95,7 +93,6 @@ class Schema
* @return ColumnDef definition of the column or null * @return ColumnDef definition of the column or null
* if not found. * if not found.
*/ */
public function getColumnDef($table, $column) public function getColumnDef($table, $column)
{ {
$td = $this->getTableDef($table); $td = $this->getTableDef($table);
@ -120,7 +117,6 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function createTable($tableName, $def) public function createTable($tableName, $def)
{ {
$statements = $this->buildCreateTable($tableName, $def); $statements = $this->buildCreateTable($tableName, $def);
@ -194,7 +190,7 @@ class Schema
* @param array $def table definition * @param array $def table definition
* @return string * @return string
*/ */
function startCreateTable($name, array $def) public function startCreateTable($name, array $def)
{ {
return 'CREATE TABLE ' . $this->quoteIdentifier($name) . ' ('; return 'CREATE TABLE ' . $this->quoteIdentifier($name) . ' (';
} }
@ -206,7 +202,7 @@ class Schema
* @param array $def table definition * @param array $def table definition
* @return string * @return string
*/ */
function endCreateTable($name, array $def) public function endCreateTable($name, array $def)
{ {
return ')'; return ')';
} }
@ -218,9 +214,9 @@ class Schema
* @param string $name * @param string $name
* @param array $def * @param array $def
*/ */
function appendColumnDef(array &$sql, $name, array $def) public function appendColumnDef(array &$sql, string $name, array $def)
{ {
$sql[] = "$name " . $this->columnSql($def); $sql[] = $name . ' ' . $this->columnSql($name, $def);
} }
/** /**
@ -230,7 +226,7 @@ class Schema
* @param array $sql * @param array $sql
* @param array $def * @param array $def
*/ */
function appendPrimaryKeyDef(array &$sql, array $def) public function appendPrimaryKeyDef(array &$sql, array $def)
{ {
$sql[] = "PRIMARY KEY " . $this->buildIndexList($def); $sql[] = "PRIMARY KEY " . $this->buildIndexList($def);
} }
@ -243,7 +239,7 @@ class Schema
* @param string $name * @param string $name
* @param array $def * @param array $def
*/ */
function appendUniqueKeyDef(array &$sql, $name, array $def) public function appendUniqueKeyDef(array &$sql, $name, array $def)
{ {
$sql[] = "CONSTRAINT $name UNIQUE " . $this->buildIndexList($def); $sql[] = "CONSTRAINT $name UNIQUE " . $this->buildIndexList($def);
} }
@ -257,7 +253,7 @@ class Schema
* @param array $def * @param array $def
* @throws Exception * @throws Exception
*/ */
function appendForeignKeyDef(array &$sql, $name, array $def) public function appendForeignKeyDef(array &$sql, $name, array $def)
{ {
if (count($def) != 2) { if (count($def) != 2) {
throw new Exception("Invalid foreign key def for $name: " . var_export($def, true)); throw new Exception("Invalid foreign key def for $name: " . var_export($def, true));
@ -265,11 +261,11 @@ class Schema
list($refTable, $map) = $def; list($refTable, $map) = $def;
$srcCols = array_keys($map); $srcCols = array_keys($map);
$refCols = array_values($map); $refCols = array_values($map);
$sql[] = "CONSTRAINT $name FOREIGN KEY " . $sql[] = 'CONSTRAINT ' . $this->quoteIdentifier($name) . ' FOREIGN KEY ' .
$this->buildIndexList($srcCols) . $this->buildIndexList($srcCols) .
" REFERENCES " . ' REFERENCES ' .
$this->quoteIdentifier($refTable) . $this->quoteIdentifier($refTable) .
" " . ' ' .
$this->buildIndexList($refCols); $this->buildIndexList($refCols);
} }
@ -282,9 +278,10 @@ class Schema
* @param string $name * @param string $name
* @param array $def * @param array $def
*/ */
function appendCreateIndex(array &$statements, $table, $name, array $def) public function appendCreateIndex(array &$statements, $table, $name, array $def)
{ {
$statements[] = "CREATE INDEX $name ON $table " . $this->buildIndexList($def); $statements[] = 'CREATE INDEX ' . $name . ' ON ' .
$this->quoteIdentifier($table) . ' ' . $this->buildIndexList($def);
} }
/** /**
@ -297,7 +294,7 @@ class Schema
* @param array $def * @param array $def
* @throws Exception * @throws Exception
*/ */
function appendCreateFulltextIndex(array &$statements, $table, $name, array $def) public function appendCreateFulltextIndex(array &$statements, $table, $name, array $def)
{ {
throw new Exception("Fulltext index not supported in this database"); throw new Exception("Fulltext index not supported in this database");
} }
@ -309,18 +306,18 @@ class Schema
* @param string $table * @param string $table
* @param string $name * @param string $name
*/ */
function appendDropIndex(array &$statements, $table, $name) public function appendDropIndex(array &$statements, $table, $name)
{ {
$statements[] = "DROP INDEX $name ON " . $this->quoteIdentifier($table); $statements[] = "DROP INDEX $name ON " . $this->quoteIdentifier($table);
} }
function buildIndexList(array $def) public function buildIndexList(array $def)
{ {
// @fixme // @fixme
return '(' . implode(',', array_map([$this, 'buildIndexItem'], $def)) . ')'; return '(' . implode(',', array_map([$this, 'buildIndexItem'], $def)) . ')';
} }
function buildIndexItem($def) public function buildIndexItem($def)
{ {
if (is_array($def)) { if (is_array($def)) {
list($name, $size) = $def; list($name, $size) = $def;
@ -339,12 +336,11 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function dropTable($name) public function dropTable($name)
{ {
global $_PEAR; global $_PEAR;
$res = $this->conn->query("DROP TABLE $name"); $res = $this->conn->query('DROP TABLE ' . $this->quoteIdentifier($name));
if ($_PEAR->isError($res)) { if ($_PEAR->isError($res)) {
PEAR_ErrorToPEAR_Exception($res); PEAR_ErrorToPEAR_Exception($res);
@ -369,7 +365,6 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function createIndex($table, $columnNames, $name = null) public function createIndex($table, $columnNames, $name = null)
{ {
global $_PEAR; global $_PEAR;
@ -382,9 +377,11 @@ class Schema
$name = "{$table}_" . implode("_", $columnNames) . "_idx"; $name = "{$table}_" . implode("_", $columnNames) . "_idx";
} }
$res = $this->conn->query("ALTER TABLE $table " . $res = $this->conn->query(
"ADD INDEX $name (" . 'ALTER TABLE ' . $this->quoteIdentifier($table) .
implode(",", $columnNames) . ")"); ' ADD INDEX ' . $name . ' (' .
implode(',', $columnNames) . ')'
);
if ($_PEAR->isError($res)) { if ($_PEAR->isError($res)) {
PEAR_ErrorToPEAR_Exception($res); PEAR_ErrorToPEAR_Exception($res);
@ -402,12 +399,14 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function dropIndex($table, $name) public function dropIndex($table, $name)
{ {
global $_PEAR; global $_PEAR;
$res = $this->conn->query("ALTER TABLE $table DROP INDEX $name"); $res = $this->conn->query(
'ALTER TABLE ' . $this->quoteIdentifier($table) .
' DROP INDEX ' . $name
);
if ($_PEAR->isError($res)) { if ($_PEAR->isError($res)) {
PEAR_ErrorToPEAR_Exception($res); PEAR_ErrorToPEAR_Exception($res);
@ -426,12 +425,12 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function addColumn($table, $columndef) public function addColumn($table, $columndef)
{ {
global $_PEAR; global $_PEAR;
$sql = "ALTER TABLE $table ADD COLUMN " . $this->_columnSql($columndef); $sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
' ADD COLUMN ' . $this->columnSql($name, $columndef);
$res = $this->conn->query($sql); $res = $this->conn->query($sql);
@ -453,13 +452,12 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function modifyColumn($table, $columndef) public function modifyColumn($table, $columndef)
{ {
global $_PEAR; global $_PEAR;
$sql = "ALTER TABLE $table MODIFY COLUMN " . $sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
$this->_columnSql($columndef); ' MODIFY COLUMN ' . $this->columnSql($name, $columndef);
$res = $this->conn->query($sql); $res = $this->conn->query($sql);
@ -481,12 +479,12 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function dropColumn($table, $columnName) public function dropColumn($table, $columnName)
{ {
global $_PEAR; global $_PEAR;
$sql = "ALTER TABLE $table DROP COLUMN $columnName"; $sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
' DROP COLUMN ' . $columnName;
$res = $this->conn->query($sql); $res = $this->conn->query($sql);
@ -511,7 +509,6 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function ensureTable($tableName, $def) public function ensureTable($tableName, $def)
{ {
$statements = $this->buildEnsureTable($tableName, $def); $statements = $this->buildEnsureTable($tableName, $def);
@ -527,7 +524,7 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function runSqlSet(array $statements) public function runSqlSet(array $statements)
{ {
global $_PEAR; global $_PEAR;
@ -561,8 +558,7 @@ class Schema
* @return array of SQL statements * @return array of SQL statements
* @throws Exception * @throws Exception
*/ */
public function buildEnsureTable($tableName, array $def)
function buildEnsureTable($tableName, array $def)
{ {
try { try {
$old = $this->getTableDef($tableName); $old = $this->getTableDef($tableName);
@ -610,14 +606,20 @@ class Schema
} }
foreach ($fields['add'] as $columnName) { foreach ($fields['add'] as $columnName) {
$this->appendAlterAddColumn($phrase, $columnName, $this->appendAlterAddColumn(
$def['fields'][$columnName]); $phrase,
$columnName,
$def['fields'][$columnName]
);
} }
foreach ($fields['mod'] as $columnName) { foreach ($fields['mod'] as $columnName) {
$this->appendAlterModifyColumn($phrase, $columnName, $this->appendAlterModifyColumn(
$phrase,
$columnName,
$old['fields'][$columnName], $old['fields'][$columnName],
$def['fields'][$columnName]); $def['fields'][$columnName]
);
} }
foreach ($fields['del'] as $columnName) { foreach ($fields['del'] as $columnName) {
@ -639,7 +641,8 @@ class Schema
$this->appendAlterExtras($phrase, $tableName, $def); $this->appendAlterExtras($phrase, $tableName, $def);
if (count($phrase) > 0) { if (count($phrase) > 0) {
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(",\n", $phrase); $sql = 'ALTER TABLE ' . $this->quoteIdentifier($tableName) .
' ' . implode(",\n", $phrase);
$statements[] = $sql; $statements[] = $sql;
} }
@ -656,7 +659,7 @@ class Schema
return $statements; return $statements;
} }
function diffArrays($oldDef, $newDef, $section, $compareCallback = null) public function diffArrays($oldDef, $newDef, $section, $compareCallback = null)
{ {
$old = isset($oldDef[$section]) ? $oldDef[$section] : []; $old = isset($oldDef[$section]) ? $oldDef[$section] : [];
$new = isset($newDef[$section]) ? $newDef[$section] : []; $new = isset($newDef[$section]) ? $newDef[$section] : [];
@ -701,7 +704,7 @@ class Schema
* @param string $columnName * @param string $columnName
* @param array $cd * @param array $cd
*/ */
function appendAlterAddColumn(array &$phrase, $columnName, array $cd) public function appendAlterAddColumn(array &$phrase, string $columnName, array $cd)
{ {
$phrase[] = 'ADD COLUMN ' . $phrase[] = 'ADD COLUMN ' .
$this->quoteIdentifier($columnName) . $this->quoteIdentifier($columnName) .
@ -718,7 +721,7 @@ class Schema
* @param array $old previous column definition as found in DB * @param array $old previous column definition as found in DB
* @param array $cd current column definition * @param array $cd current column definition
*/ */
function appendAlterModifyColumn(array &$phrase, $columnName, array $old, array $cd) public function appendAlterModifyColumn(array &$phrase, string $columnName, array $old, array $cd)
{ {
$phrase[] = 'MODIFY COLUMN ' . $phrase[] = 'MODIFY COLUMN ' .
$this->quoteIdentifier($columnName) . $this->quoteIdentifier($columnName) .
@ -733,12 +736,12 @@ class Schema
* @param array $phrase * @param array $phrase
* @param string $columnName * @param string $columnName
*/ */
function appendAlterDropColumn(array &$phrase, $columnName) public function appendAlterDropColumn(array &$phrase, $columnName)
{ {
$phrase[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName); $phrase[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName);
} }
function appendAlterAddUnique(array &$phrase, $keyName, array $def) public function appendAlterAddUnique(array &$phrase, $keyName, array $def)
{ {
$sql = []; $sql = [];
$sql[] = 'ADD'; $sql[] = 'ADD';
@ -746,7 +749,7 @@ class Schema
$phrase[] = implode(' ', $sql); $phrase[] = implode(' ', $sql);
} }
function appendAlterAddForeign(array &$phrase, $keyName, array $def) public function appendAlterAddForeign(array &$phrase, $keyName, array $def)
{ {
$sql = []; $sql = [];
$sql[] = 'ADD'; $sql[] = 'ADD';
@ -754,7 +757,7 @@ class Schema
$phrase[] = implode(' ', $sql); $phrase[] = implode(' ', $sql);
} }
function appendAlterAddPrimary(array &$phrase, array $def) public function appendAlterAddPrimary(array &$phrase, array $def)
{ {
$sql = []; $sql = [];
$sql[] = 'ADD'; $sql[] = 'ADD';
@ -762,22 +765,22 @@ class Schema
$phrase[] = implode(' ', $sql); $phrase[] = implode(' ', $sql);
} }
function appendAlterDropPrimary(array &$phrase) public function appendAlterDropPrimary(array &$phrase)
{ {
$phrase[] = 'DROP CONSTRAINT PRIMARY KEY'; $phrase[] = 'DROP CONSTRAINT PRIMARY KEY';
} }
function appendAlterDropUnique(array &$phrase, $keyName) public function appendAlterDropUnique(array &$phrase, $keyName)
{ {
$phrase[] = 'DROP CONSTRAINT ' . $keyName; $phrase[] = 'DROP CONSTRAINT ' . $keyName;
} }
function appendAlterDropForeign(array &$phrase, $keyName) public function appendAlterDropForeign(array &$phrase, $keyName)
{ {
$phrase[] = 'DROP FOREIGN KEY ' . $keyName; $phrase[] = 'DROP FOREIGN KEY ' . $keyName;
} }
function appendAlterExtras(array &$phrase, $tableName, array $def) public function appendAlterExtras(array &$phrase, $tableName, array $def)
{ {
// no-op // no-op
} }
@ -788,21 +791,21 @@ class Schema
* @param string $name * @param string $name
* @return string * @return string
*/ */
function quoteIdentifier($name) public function quoteIdentifier($name)
{ {
return $name; return $this->conn->quoteIdentifier($name);
} }
function quoteDefaultValue($cd) public function quoteDefaultValue($cd)
{ {
if (($cd['type'] == 'datetime' || $cd['type'] == 'timestamp') && $cd['default'] == 'CURRENT_TIMESTAMP') { if (in_array($cd['type'], ['datetime', 'timestamp']) && $cd['default'] === 'CURRENT_TIMESTAMP') {
return $cd['default']; return $cd['default'];
} else { } else {
return $this->quoteValue($cd['default']); return $this->quoteValue($cd['default']);
} }
} }
function quoteValue($val) public function quoteValue($val)
{ {
return $this->conn->quoteSmart($val); return $this->conn->quoteSmart($val);
} }
@ -816,7 +819,7 @@ class Schema
* @param array $b * @param array $b
* @return bool * @return bool
*/ */
function columnsEqual(array $a, array $b) public function columnsEqual(array $a, array $b)
{ {
return !array_diff_assoc($a, $b) && !array_diff_assoc($b, $a); return !array_diff_assoc($a, $b) && !array_diff_assoc($b, $a);
} }
@ -829,7 +832,6 @@ class Schema
* *
* @return array strings for name values * @return array strings for name values
*/ */
protected function _names($cds) protected function _names($cds)
{ {
$names = []; $names = [];
@ -850,7 +852,6 @@ class Schema
* *
* @return ColumnDef matching item or null if no match. * @return ColumnDef matching item or null if no match.
*/ */
protected function _byName($cds, $name) protected function _byName($cds, $name)
{ {
foreach ($cds as $cd) { foreach ($cds as $cd) {
@ -874,7 +875,7 @@ class Schema
* @return string correct SQL for that column * @return string correct SQL for that column
*/ */
function columnSql(array $cd) public function columnSql(array $cd)
{ {
$line = []; $line = [];
$line[] = $this->typeAndSize($cd); $line[] = $this->typeAndSize($cd);
@ -895,14 +896,14 @@ class Schema
* @param string $column canonical type name in defs * @param string $column canonical type name in defs
* @return string native DB type name * @return string native DB type name
*/ */
function mapType($column) public function mapType($column)
{ {
return $column; return $column;
} }
function typeAndSize($column) public function typeAndSize(array $column)
{ {
//$type = $this->mapType($column); //$type = $this->mapType($column)['type'];
$type = $column['type']; $type = $column['type'];
if (isset($column['size'])) { if (isset($column['size'])) {
$type = $column['size'] . $type; $type = $column['size'] . $type;
@ -977,12 +978,12 @@ class Schema
$table['primary key'] = []; $table['primary key'] = [];
} }
$table['primary key'][] = $cd->name; $table['primary key'][] = $cd->name;
} else if ($cd->key == 'MUL') { } elseif ($cd->key === 'MUL') {
// Individual multiple-value indexes are only per-column // Individual multiple-value indexes are only per-column
// using the old ColumnDef syntax. // using the old ColumnDef syntax.
$idx = "{$tableName}_{$cd->name}_idx"; $idx = "{$tableName}_{$cd->name}_idx";
$table['indexes'][$idx] = [$cd->name]; $table['indexes'][$idx] = [$cd->name];
} else if ($cd->key == 'UNI') { } elseif ($cd->key === 'UNI') {
// Individual unique-value indexes are only per-column // Individual unique-value indexes are only per-column
// using the old ColumnDef syntax. // using the old ColumnDef syntax.
$idx = "{$tableName}_{$cd->name}_idx"; $idx = "{$tableName}_{$cd->name}_idx";
@ -1003,7 +1004,7 @@ class Schema
* @param array $tableDef * @param array $tableDef
* @return array * @return array
*/ */
function filterDef(array $tableDef) public function filterDef(array $tableDef)
{ {
return $tableDef; return $tableDef;
} }
@ -1019,7 +1020,7 @@ class Schema
* *
* @throws Exception on wildly invalid input * @throws Exception on wildly invalid input
*/ */
function validateDef($tableName, array $def) public function validateDef($tableName, array $def)
{ {
if (isset($def[0]) && $def[0] instanceof ColumnDef) { if (isset($def[0]) && $def[0] instanceof ColumnDef) {
$def = $this->oldToNew($tableName, $def); $def = $this->oldToNew($tableName, $def);
@ -1033,7 +1034,7 @@ class Schema
return $def; return $def;
} }
function isNumericType($type) public function isNumericType($type)
{ {
$type = strtolower($type); $type = strtolower($type);
$known = ['int', 'serial', 'numeric']; $known = ['int', 'serial', 'numeric'];
@ -1081,13 +1082,14 @@ class Schema
// Already renamed, or no previous table, so we're done // Already renamed, or no previous table, so we're done
return true; return true;
} }
return $this->runSqlSet(["ALTER TABLE {$old_name} RENAME TO {$new_name};"]); return $this->runSqlSet([
'ALTER TABLE ' . $this->quoteIdentifier($old_name) .
' RENAME TO ' . $this->quoteIdentifier($new_name) . ';',
]);
} }
} }
class SchemaTableMissingException extends Exception class SchemaTableMissingException extends Exception
{ {
// no-op // no-op
} }

View File

@ -1,48 +1,40 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Section for featured users * Section for featured users
* *
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget * @category Widget
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Section for featured users * Section for featured users
* *
* @category Widget * @copyright 2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/ */
class FeaturedUsersSection extends ProfileSection class FeaturedUsersSection extends ProfileSection
{ {
function show() public function show()
{ {
$featured_nicks = common_config('nickname', 'featured'); $featured_nicks = common_config('nickname', 'featured');
if (empty($featured_nicks)) { if (empty($featured_nicks)) {
@ -51,7 +43,7 @@ class FeaturedUsersSection extends ProfileSection
parent::show(); parent::show();
} }
function getProfiles() public function getProfiles()
{ {
$featured_nicks = common_config('nickname', 'featured'); $featured_nicks = common_config('nickname', 'featured');
@ -65,43 +57,30 @@ class FeaturedUsersSection extends ProfileSection
$quoted[] = "'$nick'"; $quoted[] = "'$nick'";
} }
$table = "user"; $table = common_database_tablename('user');
if(common_config('db','quote_identifiers')) { $limit = PROFILES_PER_SECTION + 1;
$table = '"' . $table . '"';
}
$qry = 'SELECT profile.* ' . $qry = 'SELECT profile.* ' .
'FROM profile JOIN '. $table .' on profile.id = '. $table .'.id ' . 'FROM profile INNER JOIN ' . $table . ' ON profile.id = ' . $table . '.id ' .
'WHERE '. $table .'.nickname in (' . implode(',', $quoted) . ') ' . 'WHERE ' . $table . '.nickname IN (' . implode(',', $quoted) . ') ' .
'ORDER BY profile.created DESC '; 'ORDER BY profile.created DESC LIMIT ' . $limit;
$limit = PROFILES_PER_SECTION + 1; $profile = Memcached_DataObject::cachedQuery('Profile', $qry, 6 * 3600);
$offset = 0;
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = Memcached_DataObject::cachedQuery('Profile',
$qry,
6 * 3600);
return $profile; return $profile;
} }
function title() public function title()
{ {
// TRANS: Title for featured users section. // TRANS: Title for featured users section.
return _('Featured users'); return _('Featured users');
} }
function divId() public function divId()
{ {
return 'featured_users'; return 'featured_users';
} }
function moreUrl() public function moreUrl()
{ {
return common_local_url('featured'); return common_local_url('featured');
} }

View File

@ -1,29 +1,29 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* GNU social - a federating social network
*
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Config * @category Config
* @package GNUsocial * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org * @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link https://www.gnu.org/software/social/
*/ */
defined('GNUSOCIAL') || die();
$default = $default =
array('site' => array('site' =>
array('name' => 'Just another GNU social node', array('name' => 'Just another GNU social node',
@ -74,7 +74,7 @@ $default =
'mirror' => null, 'mirror' => null,
'utf8' => true, 'utf8' => true,
'db_driver' => 'DB', # XXX: JanRain libs only work with DB 'db_driver' => 'DB', # XXX: JanRain libs only work with DB
'quote_identifiers' => false, 'quote_identifiers' => true,
'type' => 'mysql', 'type' => 'mysql',
'schemacheck' => 'runtime', // 'runtime' or 'script' 'schemacheck' => 'runtime', // 'runtime' or 'script'
'annotate_queries' => false, // true to add caller comments to queries, eg /* POST Notice::saveNew */ 'annotate_queries' => false, // true to add caller comments to queries, eg /* POST Notice::saveNew */

View File

@ -446,7 +446,6 @@ abstract class Installer
// database // database
"\$config['db']['database'] = {$vals['db_database']};\n\n" . "\$config['db']['database'] = {$vals['db_database']};\n\n" .
($this->db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n" : '') .
"\$config['db']['type'] = {$vals['db_type']};\n\n" . "\$config['db']['type'] = {$vals['db_type']};\n\n" .
"// Uncomment below for better performance. Just remember you must run\n" . "// Uncomment below for better performance. Just remember you must run\n" .
@ -457,7 +456,7 @@ abstract class Installer
$cfg = str_replace("\n", PHP_EOL, $cfg); $cfg = str_replace("\n", PHP_EOL, $cfg);
// write configuration file out to install directory // write configuration file out to install directory
$res = file_put_contents(INSTALLDIR . '/config.php', $cfg); $res = file_put_contents(INSTALLDIR . DIRECTORY_SEPARATOR . 'config.php', $cfg);
return $res; return $res;
} }

View File

@ -1,36 +1,33 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool * Utilities for sending email
*
* utilities for sending email
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @category Mail * @category Mail
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Robin Millette <millette@status.net> * @author Robin Millette <millette@status.net>
* @author Sarven Capadisli <csarven@status.net> * @author Sarven Capadisli <csarven@status.net>
* @copyright 2008 StatusNet, Inc. * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
require_once 'Mail.php'; require_once 'Mail.php';
@ -49,8 +46,10 @@ function mail_backend()
if (!$backend) { if (!$backend) {
$mail = new Mail(); $mail = new Mail();
$backend = $mail->factory(common_config('mail', 'backend'), $backend = $mail->factory(
common_config('mail', 'params') ?: array()); common_config('mail', 'backend'),
common_config('mail', 'params') ?: []
);
if ($_PEAR->isError($backend)) { if ($_PEAR->isError($backend)) {
throw new EmailException($backend->getMessage(), $backend->getCode()); throw new EmailException($backend->getMessage(), $backend->getCode());
} }
@ -124,7 +123,6 @@ function mail_notify_from()
$notifyfrom = common_config('mail', 'notifyfrom'); $notifyfrom = common_config('mail', 'notifyfrom');
if (!$notifyfrom) { if (!$notifyfrom) {
$domain = mail_domain(); $domain = mail_domain();
$notifyfrom = '"'. str_replace('"', '\\"', common_config('site', 'name')) .'" <noreply@'.$domain.'>'; $notifyfrom = '"'. str_replace('"', '\\"', common_config('site', 'name')) .'" <noreply@'.$domain.'>';
@ -194,7 +192,6 @@ function mail_subscribe_notify_profile($listenee, $other)
{ {
if ($other->hasRight(Right::EMAILONSUBSCRIBE) && if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
$listenee->email && $listenee->emailnotifysub) { $listenee->email && $listenee->emailnotifysub) {
$profile = $listenee->getProfile(); $profile = $listenee->getProfile();
$name = $profile->getBestName(); $name = $profile->getBestName();
@ -211,15 +208,19 @@ function mail_subscribe_notify_profile($listenee, $other)
$headers['To'] = $name . ' <' . $listenee->email . '>'; $headers['To'] = $name . ' <' . $listenee->email . '>';
// TRANS: Subject of new-subscriber notification e-mail. // TRANS: Subject of new-subscriber notification e-mail.
// TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename. // TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s is now following you on %2$s.'), $headers['Subject'] = sprintf(
_('%1$s is now following you on %2$s.'),
$other->getBestName(), $other->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of new-subscriber notification e-mail. // TRANS: Main body of new-subscriber notification e-mail.
// TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename. // TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
$body = sprintf(_('%1$s is now following you on %2$s.'), $body = sprintf(
_('%1$s is now following you on %2$s.'),
$long_name, $long_name,
common_config('site', 'name')) . common_config('site', 'name')
) .
mail_profile_block($other) . mail_profile_block($other) .
mail_footer_block(); mail_footer_block();
@ -233,7 +234,6 @@ function mail_subscribe_pending_notify_profile($listenee, $other)
{ {
if ($other->hasRight(Right::EMAILONSUBSCRIBE) && if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
$listenee->email && $listenee->emailnotifysub) { $listenee->email && $listenee->emailnotifysub) {
$profile = $listenee->getProfile(); $profile = $listenee->getProfile();
$name = $profile->getBestName(); $name = $profile->getBestName();
@ -251,18 +251,22 @@ function mail_subscribe_pending_notify_profile($listenee, $other)
$headers['To'] = $name . ' <' . $listenee->email . '>'; $headers['To'] = $name . ' <' . $listenee->email . '>';
// TRANS: Subject of pending new-subscriber notification e-mail. // TRANS: Subject of pending new-subscriber notification e-mail.
// TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename. // TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s would like to listen to '. $headers['Subject'] = sprintf(
_('%1$s would like to listen to '.
'your notices on %2$s.'), 'your notices on %2$s.'),
$other->getBestName(), $other->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of pending new-subscriber notification e-mail. // TRANS: Main body of pending new-subscriber notification e-mail.
// TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename. // TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
$body = sprintf(_('%1$s would like to listen to your notices on %2$s. ' . $body = sprintf(
_('%1$s would like to listen to your notices on %2$s. ' .
'You may approve or reject their subscription at %3$s'), 'You may approve or reject their subscription at %3$s'),
$long_name, $long_name,
common_config('site', 'name'), common_config('site', 'name'),
common_local_url('subqueue', array('nickname' => $listenee->nickname))) . common_local_url('subqueue', ['nickname' => $listenee->nickname])
) .
mail_profile_block($other) . mail_profile_block($other) .
mail_footer_block(); mail_footer_block();
@ -277,13 +281,15 @@ function mail_footer_block()
// TRANS: Common footer block for StatusNet notification emails. // TRANS: Common footer block for StatusNet notification emails.
// TRANS: %1$s is the StatusNet sitename, // TRANS: %1$s is the StatusNet sitename,
// TRANS: %2$s is a link to the addressed user's e-mail settings. // TRANS: %2$s is a link to the addressed user's e-mail settings.
return "\n\n" . sprintf(_('Faithfully yours,'. return "\n\n" . sprintf(
_('Faithfully yours,'.
"\n".'%1$s.'."\n\n". "\n".'%1$s.'."\n\n".
"----\n". "----\n".
"Change your email address or ". "Change your email address or ".
"notification options at ".'%2$s'), "notification options at ".'%2$s'),
common_config('site', 'name'), common_config('site', 'name'),
common_local_url('emailsettings')) . "\n"; common_local_url('emailsettings')
) . "\n";
} }
/** /**
@ -326,10 +332,12 @@ function mail_profile_block($profile)
// TRANS: This is a paragraph in a new-subscriber e-mail. // TRANS: This is a paragraph in a new-subscriber e-mail.
// TRANS: %s is a URL where the subscriber can be reported as abusive. // TRANS: %s is a URL where the subscriber can be reported as abusive.
$out[] = sprintf(_('If you believe this account is being used abusively, ' . $out[] = sprintf(
_('If you believe this account is being used abusively, ' .
'you can block them from your subscribers list and ' . 'you can block them from your subscribers list and ' .
'report as spam to site administrators at %s.'), 'report as spam to site administrators at %s.'),
$blocklink); $blocklink
);
$out[] = ""; $out[] = "";
return implode("\n", $out); return implode("\n", $out);
@ -354,18 +362,22 @@ function mail_new_incoming_notify($user)
$headers['To'] = $name . ' <' . $user->email . '>'; $headers['To'] = $name . ' <' . $user->email . '>';
// TRANS: Subject of notification mail for new posting email address. // TRANS: Subject of notification mail for new posting email address.
// TRANS: %s is the StatusNet sitename. // TRANS: %s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('New email address for posting to %s'), $headers['Subject'] = sprintf(
common_config('site', 'name')); _('New email address for posting to %s'),
common_config('site', 'name')
);
// TRANS: Body of notification mail for new posting email address. // TRANS: Body of notification mail for new posting email address.
// TRANS: %1$s is the StatusNet sitename, %2$s is the e-mail address to send // TRANS: %1$s is the StatusNet sitename, %2$s is the e-mail address to send
// TRANS: to to post by e-mail, %3$s is a URL to more instructions. // TRANS: to to post by e-mail, %3$s is a URL to more instructions.
$body = sprintf(_("You have a new posting address on %1\$s.\n\n". $body = sprintf(
_("You have a new posting address on %1\$s.\n\n".
"Send email to %2\$s to post new messages.\n\n". "Send email to %2\$s to post new messages.\n\n".
"More email instructions at %3\$s."), "More email instructions at %3\$s."),
common_config('site', 'name'), common_config('site', 'name'),
$user->incomingemail, $user->incomingemail,
common_local_url('doc', array('title' => 'email'))) . common_local_url('doc', ['title' => 'email'])
) .
mail_footer_block(); mail_footer_block();
mail_send($user->email, $headers, $body); mail_send($user->email, $headers, $body);
@ -402,42 +414,58 @@ function mail_broadcast_notice_sms($notice)
$user = new User(); $user = new User();
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$replies = $notice->getReplies(); $replies = $notice->getReplies();
$user->query('SELECT nickname, smsemail, incomingemail ' .
"FROM $UT LEFT OUTER JOIN subscription " . $repliesQry = '';
"ON $UT.id = subscription.subscriber " . if (!empty($replies)) {
'AND subscription.subscribed = ' . $notice->profile_id . ' ' . $repliesQry = sprintf(
'AND subscription.subscribed != subscription.subscriber ' . 'OR %s.id IN (%s)',
$user->escapedTableName(),
implode(',', $replies)
);
}
$user->query(sprintf(
'SELECT nickname, smsemail, incomingemail ' .
'FROM %1$s LEFT JOIN subscription ' .
'ON %1$s.id = subscription.subscriber ' .
'AND subscription.subscribed = %2$d ' .
'AND subscription.subscribed <> subscription.subscriber ' .
// Users (other than the sender) who `want SMS notices': // Users (other than the sender) who `want SMS notices':
"WHERE $UT.id != " . $notice->profile_id . ' ' . 'WHERE %1$s.id <> %2$d ' .
"AND $UT.smsemail IS NOT null " . 'AND %1$s.smsemail IS NOT NULL ' .
"AND $UT.smsnotify = 1 " . 'AND %1$s.smsnotify = 1 ' .
// ... where either the user _is_ subscribed to the sender // ... where either the user _is_ subscribed to the sender
// (any of the "subscription" fields IS NOT null) // (any of the "subscription" fields IS NOT NULL)
// and wants to get SMS for all of this scribe's notices... // and wants to get SMS for all of this scribe's notices...
'AND (subscription.sms = 1 ' . 'AND (subscription.sms = 1 ' .
// ... or where the user was mentioned in // ... or where the user was mentioned in
// or replied-to with the notice: // or replied-to with the notice:
($replies ? sprintf("OR $UT.id in (%s)", $repliesQry .
implode(',', $replies)) ')',
: '') . $user->escapedTableName(),
')'); $notice->profile_id
));
while ($user->fetch()) { while ($user->fetch()) {
common_log(LOG_INFO, common_log(
LOG_INFO,
'Sending notice ' . $notice->id . ' to ' . $user->smsemail, 'Sending notice ' . $notice->id . ' to ' . $user->smsemail,
__FILE__); __FILE__
$success = mail_send_sms_notice_address($notice, );
$success = mail_send_sms_notice_address(
$notice,
$user->smsemail, $user->smsemail,
$user->incomingemail, $user->incomingemail,
$user->nickname); $user->nickname
);
if (!$success) { if (!$success) {
// XXX: Not sure, but I think that's the right thing to do // XXX: Not sure, but I think that's the right thing to do
common_log(LOG_WARNING, common_log(
'Sending notice ' . $notice->id . ' to ' . LOG_WARNING,
$user->smsemail . ' FAILED, cancelling.', 'Sending notice ' . $notice->id . ' to ' . $user->smsemail . ' FAILED, canceling.',
__FILE__); __FILE__
);
return false; return false;
} }
} }
@ -462,10 +490,12 @@ function mail_broadcast_notice_sms($notice)
*/ */
function mail_send_sms_notice($notice, $user) function mail_send_sms_notice($notice, $user)
{ {
return mail_send_sms_notice_address($notice, return mail_send_sms_notice_address(
$notice,
$user->smsemail, $user->smsemail,
$user->incomingemail, $user->incomingemail,
$user->nickname); $user->nickname
);
} }
/** /**
@ -496,8 +526,7 @@ function mail_send_sms_notice_address($notice, $smsemail, $incomingemail, $nickn
$headers['To'] = $to; $headers['To'] = $to;
// TRANS: Subject line for SMS-by-email notification messages. // TRANS: Subject line for SMS-by-email notification messages.
// TRANS: %s is the posting user's nickname. // TRANS: %s is the posting user's nickname.
$headers['Subject'] = sprintf(_('%s status'), $headers['Subject'] = sprintf(_('%s status'), $other->getBestName());
$other->getBestName());
$body = $notice->content; $body = $notice->content;
@ -554,14 +583,16 @@ function mail_notify_nudge($from, $to)
// TRANS: Body for 'nudge' notification email. // TRANS: Body for 'nudge' notification email.
// TRANS: %1$s is the nuding user's long name, $2$s is the nudging user's nickname, // TRANS: %1$s is the nuding user's long name, $2$s is the nudging user's nickname,
// TRANS: %3$s is a URL to post notices at. // TRANS: %3$s is a URL to post notices at.
$body = sprintf(_("%1\$s (%2\$s) is wondering what you are up to ". $body = sprintf(
_('%1$s (%2$s) is wondering what you are up to ' .
"these days and is inviting you to post some news.\n\n" . "these days and is inviting you to post some news.\n\n" .
"So let's hear from you :)\n\n" . "So let's hear from you :)\n\n" .
"%3\$s\n\n" . "%3\$s\n\n" .
"Don't reply to this email; it won't get to them."), "Don't reply to this email; it won't get to them."),
$from_profile->getBestName(), $from_profile->getBestName(),
$from->nickname, $from->nickname,
common_local_url('all', array('nickname' => $to->nickname))) . common_local_url('all', ['nickname' => $to->nickname])
) .
mail_footer_block(); mail_footer_block();
common_switch_locale(); common_switch_locale();
@ -612,7 +643,8 @@ function mail_notify_message(Notice $message, Profile $from = null, ?array $to =
// TRANS: Body for direct-message notification email. // TRANS: Body for direct-message notification email.
// TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname, // TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname,
// TRANS: %3$s is the message content, %4$s a URL to the message, // TRANS: %3$s is the message content, %4$s a URL to the message,
$body = sprintf(_("%1\$s (%2\$s) sent you a private message:\n\n". $body = sprintf(
_("%1\$s (%2\$s) sent you a private message:\n\n".
"------------------------------------------------------\n". "------------------------------------------------------\n".
"%3\$s\n". "%3\$s\n".
"------------------------------------------------------\n\n". "------------------------------------------------------\n\n".
@ -622,7 +654,8 @@ function mail_notify_message(Notice $message, Profile $from = null, ?array $to =
$from->getBestName(), $from->getBestName(),
$from->getNickname(), $from->getNickname(),
$message->getContent(), $message->getContent(),
common_local_url('newmessage', ['to' => $from->getID()])) . common_local_url('newmessage', ['to' => $from->getID()])
) .
mail_footer_block(); mail_footer_block();
$headers = _mail_prepare_headers('message', $t->getNickname(), $from->getNickname()); $headers = _mail_prepare_headers('message', $t->getNickname(), $from->getNickname());
@ -675,8 +708,11 @@ function mail_notify_attn(Profile $rcpt, Notice $notice)
common_switch_locale($user->language); common_switch_locale($user->language);
if ($notice->hasConversation()) { if ($notice->hasConversation()) {
$conversationUrl = common_local_url('conversation', $conversationUrl = common_local_url(
array('id' => $notice->conversation)).'#notice-'.$notice->getID(); 'conversation',
['id' => $notice->conversation]
) . '#notice-'.$notice->getID();
// TRANS: Line in @-reply notification e-mail. %s is conversation URL. // TRANS: Line in @-reply notification e-mail. %s is conversation URL.
$conversationEmailText = sprintf(_("The full conversation can be read here:\n\n". $conversationEmailText = sprintf(_("The full conversation can be read here:\n\n".
"\t%s"), $conversationUrl) . "\n\n"; "\t%s"), $conversationUrl) . "\n\n";
@ -689,11 +725,12 @@ function mail_notify_attn(Profile $rcpt, Notice $notice)
$subject = sprintf(_('%1$s sent a notice to your attention'), $sender->getFancyName()); $subject = sprintf(_('%1$s sent a notice to your attention'), $sender->getFancyName());
// TRANS: Body of @-reply notification e-mail. // TRANS: Body of @-reply notification e-mail.
// TRANS: %1$s is the sending user's name, $2$s is the StatusNet sitename, // TRANS: %1$s is the sending user's name, $2$s is the GNU social sitename,
// TRANS: %3$s is a URL to the notice, %4$s is the notice text, // TRANS: %3$s is a URL to the notice, %4$s is the notice text,
// TRANS: %5$s is the text "The full conversation can be read here:" and a URL to the full conversion if it exists (otherwise empty), // TRANS: %5$s is the text "The full conversation can be read here:" and a URL to the full conversion if it exists (otherwise empty),
// TRANS: %6$s is a URL to reply to the notice, %7$s is a URL to all @-replies for the addressed user, // TRANS: %6$s is a URL to reply to the notice, %7$s is a URL to all @-replies for the addressed user,
$body = sprintf(_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n". $body = sprintf(
_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
"The notice is here:\n\n". "The notice is here:\n\n".
"\t%3\$s\n\n" . "\t%3\$s\n\n" .
"It reads:\n\n". "It reads:\n\n".
@ -705,14 +742,21 @@ function mail_notify_attn(Profile $rcpt, Notice $notice)
"%7\$s"), "%7\$s"),
$sender->getFancyName(), //%1 $sender->getFancyName(), //%1
common_config('site', 'name'), //%2 common_config('site', 'name'), //%2
common_local_url('shownotice', common_local_url(
array('notice' => $notice->getID())),//%3 'shownotice',
['notice' => $notice->getID()]
), //%3
$notice->getContent(), //%4 $notice->getContent(), //%4
$conversationEmailText, //%5 $conversationEmailText, //%5
common_local_url('newnotice', common_local_url(
array('replyto' => $sender->getNickname(), 'inreplyto' => $notice->getID())),//%6 'newnotice',
common_local_url('replies', ['replyto' => $sender->getNickname(), 'inreplyto' => $notice->getID()]
array('nickname' => $rcpt->getNickname()))) . //%7 ), //%6
common_local_url(
'replies',
['nickname' => $rcpt->getNickname()]
)
) . //%7
mail_footer_block(); mail_footer_block();
$headers = _mail_prepare_headers('mention', $rcpt->getNickname(), $sender->getNickname()); $headers = _mail_prepare_headers('mention', $rcpt->getNickname(), $sender->getNickname());
@ -764,20 +808,23 @@ function mail_notify_group_join($group, $joiner)
$headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>'; $headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
// TRANS: Subject of group join notification e-mail. // TRANS: Subject of group join notification e-mail.
// TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename. // TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s has joined '. $headers['Subject'] = sprintf(
'your group %2$s on %3$s'), _('%1$s has joined your group %2$s on %3$s'),
$joiner->getBestName(), $joiner->getBestName(),
$group->getBestName(), $group->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of group join notification e-mail. // TRANS: Main body of group join notification e-mail.
// TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename, // TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename,
// TRANS: %4$s is a block of profile info about the subscriber. // TRANS: %4$s is a block of profile info about the subscriber.
// TRANS: %5$s is a link to the addressed user's e-mail settings. // TRANS: %5$s is a link to the addressed user's e-mail settings.
$body = sprintf(_('%1$s has joined your group %2$s on %3$s.'), $body = sprintf(
_('%1$s has joined your group %2$s on %3$s.'),
$joiner->getFancyName(), $joiner->getFancyName(),
$group->getFancyName(), $group->getFancyName(),
common_config('site', 'name')) . common_config('site', 'name')
) .
mail_profile_block($joiner) . mail_profile_block($joiner) .
mail_footer_block(); mail_footer_block();
@ -811,20 +858,24 @@ function mail_notify_group_join_pending($group, $joiner)
$headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>'; $headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
// TRANS: Subject of pending group join request notification e-mail. // TRANS: Subject of pending group join request notification e-mail.
// TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename. // TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s wants to join your group %2$s on %3$s.'), $headers['Subject'] = sprintf(
_('%1$s wants to join your group %2$s on %3$s.'),
$joiner->getBestName(), $joiner->getBestName(),
$group->getBestName(), $group->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of pending group join request notification e-mail. // TRANS: Main body of pending group join request notification e-mail.
// TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename, // TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename,
// TRANS: %4$s is the URL to the moderation queue page. // TRANS: %4$s is the URL to the moderation queue page.
$body = sprintf(_('%1$s would like to join your group %2$s on %3$s. ' . $body = sprintf(
_('%1$s would like to join your group %2$s on %3$s. ' .
'You may approve or reject their group membership at %4$s'), 'You may approve or reject their group membership at %4$s'),
$joiner->getFancyName(), $joiner->getFancyName(),
$group->getFancyName(), $group->getFancyName(),
common_config('site', 'name'), common_config('site', 'name'),
common_local_url('groupqueue', array('nickname' => $group->nickname))) . common_local_url('groupqueue', ['nickname' => $group->nickname])
) .
mail_profile_block($joiner) . mail_profile_block($joiner) .
mail_footer_block(); mail_footer_block();

View File

@ -1,24 +1,23 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008-2011, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
* GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License
* // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* XXX: break up into separate modules (HTTP, user, files) */ /* XXX: break up into separate modules (HTTP, user, files) */
defined('GNUSOCIAL') || die();
/** /**
* Show a server error. * Show a server error.
*/ */
@ -52,12 +51,14 @@ function common_init_locale($language=null)
} }
putenv('LANGUAGE='.$language); putenv('LANGUAGE='.$language);
putenv('LANG='.$language); putenv('LANG='.$language);
$ok = setlocale(LC_ALL, $ok = setlocale(
$language . ".utf8", LC_ALL,
$language . ".UTF8", $language . '.utf8',
$language . ".utf-8", $language . '.UTF8',
$language . ".UTF-8", $language . '.utf-8',
$language); $language . '.UTF-8',
$language
);
return $ok; return $ok;
} }
@ -356,12 +357,14 @@ function common_set_cookie($key, $value, $expiration=0)
} else { } else {
$cookiepath = '/'; $cookiepath = '/';
} }
return setcookie($key, return setcookie(
$key,
$value, $value,
$expiration, $expiration,
$cookiepath, $cookiepath,
$server, $server,
GNUsocial::useHTTPS()); GNUsocial::useHTTPS()
);
} }
define('REMEMBERME', 'rememberme'); define('REMEMBERME', 'rememberme');
@ -592,7 +595,6 @@ function common_to_alphanumeric($str)
function common_purify($html, array $args=[]) function common_purify($html, array $args=[])
{ {
$cfg = \HTMLPurifier_Config::createDefault(); $cfg = \HTMLPurifier_Config::createDefault();
/** /**
* rel values that should be avoided since they can be used to infer * rel values that should be avoided since they can be used to infer
@ -839,9 +841,10 @@ function common_find_mentions($text, Profile $sender, Notice $parent=null)
} }
$tagged = $sender->getTaggedSubscribers($tag); $tagged = $sender->getTaggedSubscribers($tag);
$url = common_local_url('showprofiletag', $url = common_local_url(
['nickname' => $sender->getNickname(), 'showprofiletag',
'tag' => $tag]); ['nickname' => $sender->getNickname(), 'tag' => $tag]
);
$mentions[] = ['mentioned' => $tagged, $mentions[] = ['mentioned' => $tagged,
'type' => 'list', 'type' => 'list',
@ -888,17 +891,21 @@ function common_find_mentions($text, Profile $sender, Notice $parent=null)
function common_find_mentions_raw($text, $preMention='@') function common_find_mentions_raw($text, $preMention='@')
{ {
$tmatches = []; $tmatches = [];
preg_match_all('/^T (' . Nickname::DISPLAY_FMT . ') /', preg_match_all(
'/^T (' . Nickname::DISPLAY_FMT . ') /',
$text, $text,
$tmatches, $tmatches,
PREG_OFFSET_CAPTURE); PREG_OFFSET_CAPTURE
);
$atmatches = []; $atmatches = [];
// the regexp's "(?!\@)" makes sure it doesn't matches the single "@remote" in "@remote@server.com" // the regexp's "(?!\@)" makes sure it doesn't matches the single "@remote" in "@remote@server.com"
preg_match_all('/'.Nickname::BEFORE_MENTIONS.preg_quote($preMention, '/').'(' . Nickname::DISPLAY_FMT . ')\b(?!\@)/', preg_match_all(
'/' . Nickname::BEFORE_MENTIONS . preg_quote($preMention, '/') . '(' . Nickname::DISPLAY_FMT . ')\b(?!\@)/',
$text, $text,
$atmatches, $atmatches,
PREG_OFFSET_CAPTURE); PREG_OFFSET_CAPTURE
);
$matches = array_merge($tmatches[1], $atmatches[1]); $matches = array_merge($tmatches[1], $atmatches[1]);
return $matches; return $matches;
@ -961,7 +968,8 @@ function common_url_schemes($filter = null)
$schemes, $schemes,
function ($scheme) use ($filter) { function ($scheme) use ($filter) {
return is_null($filter) || ($scheme & $filter); return is_null($filter) || ($scheme & $filter);
}) }
)
); );
} }
@ -1339,8 +1347,10 @@ function common_relative_profile($sender, $nickname, $dt=null)
// Try to find profiles this profile is subscribed to that have this nickname // Try to find profiles this profile is subscribed to that have this nickname
$recipient = new Profile(); $recipient = new Profile();
// XXX: use a join instead of a subquery $recipient->whereAdd(
$recipient->whereAdd('EXISTS (SELECT subscribed from subscription where subscriber = '.intval($sender->id).' and subscribed = id)', 'AND'); sprintf('id IN (SELECT subscribed FROM subscription WHERE subscriber = %d)', $sender->id),
'AND'
);
$recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND'); $recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND');
if ($recipient->find(true)) { if ($recipient->find(true)) {
// XXX: should probably differentiate between profiles with // XXX: should probably differentiate between profiles with
@ -1349,8 +1359,10 @@ function common_relative_profile($sender, $nickname, $dt=null)
} }
// Try to find profiles that listen to this profile and that have this nickname // Try to find profiles that listen to this profile and that have this nickname
$recipient = new Profile(); $recipient = new Profile();
// XXX: use a join instead of a subquery $recipient->whereAdd(
$recipient->whereAdd('EXISTS (SELECT subscriber from subscription where subscribed = '.intval($sender->id).' and subscriber = id)', 'AND'); sprintf('id IN (SELECT subscriber FROM subscription WHERE subscribed = %d)', $sender->id),
'AND'
);
$recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND'); $recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND');
if ($recipient->find(true)) { if ($recipient->find(true)) {
// XXX: should probably differentiate between profiles with // XXX: should probably differentiate between profiles with
@ -1701,11 +1713,13 @@ function common_enqueue_notice($notice)
function common_profile_url($nickname) function common_profile_url($nickname)
{ {
return common_local_url('showstream', return common_local_url(
'showstream',
['nickname' => $nickname], ['nickname' => $nickname],
null, null,
null, null,
false); false
);
} }
/** /**
@ -2210,11 +2224,13 @@ function common_remove_magic_from_request()
function common_user_uri(&$user) function common_user_uri(&$user)
{ {
return common_local_url('userbyid', return common_local_url(
'userbyid',
['id' => $user->id], ['id' => $user->id],
null, null,
null, null,
false); false
);
} }
/** /**
@ -2225,7 +2241,8 @@ function common_user_uri(&$user)
* alphanums and remove lookalikes (0, O, 1, I) = 32 chars = 5 bits to make it easy for the user to type in * alphanums and remove lookalikes (0, O, 1, I) = 32 chars = 5 bits to make it easy for the user to type in
* @return string confirmation_code of length $bits/5 * @return string confirmation_code of length $bits/5
*/ */
function common_confirmation_code($bits, $codechars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ') { function common_confirmation_code($bits, $codechars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ')
{
$chars = ceil($bits/5); $chars = ceil($bits/5);
$codechars_length = strlen($codechars)-1; $codechars_length = strlen($codechars)-1;
$code = ''; $code = '';
@ -2403,15 +2420,13 @@ function common_compatible_license($from, $to)
} }
/** /**
* returns a quoted table name, if required according to config * returns a quoted table name
*/ */
function common_database_tablename($tablename) function common_database_tablename($tablename)
{ {
if (common_config('db', 'quote_identifiers')) { $schema = Schema::get();
$tablename = '"'. $tablename .'"';
}
// table prefixes could be added here later // table prefixes could be added here later
return $tablename; return $schema->quoteIdentifier($tablename);
} }
/** /**
@ -2692,10 +2707,13 @@ function _common_size_str_to_int($size): int
* *
* @return int * @return int
*/ */
function common_get_preferred_php_upload_limit(): int { function common_get_preferred_php_upload_limit(): int
return min(_common_size_str_to_int(ini_get('post_max_size')), {
return min(
_common_size_str_to_int(ini_get('post_max_size')),
_common_size_str_to_int(ini_get('upload_max_filesize')), _common_size_str_to_int(ini_get('upload_max_filesize')),
_common_size_str_to_int(ini_get('memory_limit'))); _common_size_str_to_int(ini_get('memory_limit'))
);
} }
function html_sprintf() function html_sprintf()

View File

@ -326,15 +326,18 @@ class Nodeinfo_2_0Action extends Action
*/ */
public function getActiveUsers(int $days): int public function getActiveUsers(int $days): int
{ {
$userTable = common_database_tablename('user');
$query = " $query = "
SELECT COUNT(DISTINCT profile_id) as active_users_count SELECT COUNT(DISTINCT profile_id) AS active_users_count
FROM ( FROM (
SELECT profile_id FROM notice WHERE notice.created >= NOW() - INTERVAL {$days} DAY AND notice.is_local = 1 SELECT profile_id FROM notice
WHERE notice.created >= (CURRENT_TIMESTAMP - INTERVAL {$days} DAY) AND notice.is_local = 1
UNION ALL UNION ALL
SELECT user_id FROM fave INNER JOIN user ON fave.user_id = user.id WHERE fave.created >= NOW() - INTERVAL {$days} DAY SELECT user_id FROM fave INNER JOIN {$userTable} ON fave.user_id = {$userTable}.id
WHERE fave.created >= (CURRENT_TIMESTAMP - INTERVAL {$days} DAY)
UNION ALL UNION ALL
SELECT id FROM user WHERE user.created >= NOW() - INTERVAL {$days} DAY SELECT id FROM {$userTable} WHERE {$userTable}.created >= (CURRENT_TIMESTAMP - INTERVAL {$days} DAY)
) as source"; ) AS source";
$activeUsersCount = new DB_DataObject(); $activeUsersCount = new DB_DataObject();
$activeUsersCount->query($query); $activeUsersCount->query($query);