ApiQueryAllUsers.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php
  2. /*
  3. * Created on July 7, 2007
  4. *
  5. * API for MediaWiki 1.8+
  6. *
  7. * Copyright (C) 2007 Yuri Astrakhan <Firstname><Lastname>@gmail.com
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program; if not, write to the Free Software Foundation, Inc.,
  21. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. * http://www.gnu.org/copyleft/gpl.html
  23. */
  24. if (!defined('MEDIAWIKI')) {
  25. // Eclipse helper - will be ignored in production
  26. require_once ('ApiQueryBase.php');
  27. }
  28. /**
  29. * Query module to enumerate all registered users.
  30. *
  31. * @ingroup API
  32. */
  33. class ApiQueryAllUsers extends ApiQueryBase {
  34. public function __construct($query, $moduleName) {
  35. parent :: __construct($query, $moduleName, 'au');
  36. }
  37. public function execute() {
  38. $db = $this->getDB();
  39. $params = $this->extractRequestParams();
  40. $prop = $params['prop'];
  41. if (!is_null($prop)) {
  42. $prop = array_flip($prop);
  43. $fld_blockinfo = isset($prop['blockinfo']);
  44. $fld_editcount = isset($prop['editcount']);
  45. $fld_groups = isset($prop['groups']);
  46. $fld_registration = isset($prop['registration']);
  47. } else {
  48. $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = false;
  49. }
  50. $limit = $params['limit'];
  51. $this->addTables('user', 'u1');
  52. if (!is_null($params['from']))
  53. $this->addWhere('u1.user_name >= ' . $db->addQuotes($this->keyToTitle($params['from'])));
  54. if (!is_null($params['prefix']))
  55. $this->addWhere('u1.user_name LIKE "' . $db->escapeLike($this->keyToTitle( $params['prefix'])) . '%"');
  56. if (!is_null($params['group'])) {
  57. // Filter only users that belong to a given group
  58. $this->addTables('user_groups', 'ug1');
  59. $this->addWhere('ug1.ug_user=u1.user_id');
  60. $this->addWhereFld('ug1.ug_group', $params['group']);
  61. }
  62. if ($params['witheditsonly'])
  63. $this->addWhere('user_editcount > 0');
  64. if ($fld_groups) {
  65. // Show the groups the given users belong to
  66. // request more than needed to avoid not getting all rows that belong to one user
  67. $groupCount = count(User::getAllGroups());
  68. $sqlLimit = $limit+$groupCount+1;
  69. $this->addTables('user_groups', 'ug2');
  70. $tname = $this->getAliasedName('user_groups', 'ug2');
  71. $this->addJoinConds(array($tname => array('LEFT JOIN', 'ug2.ug_user=u1.user_id')));
  72. $this->addFields('ug2.ug_group ug_group2');
  73. } else {
  74. $sqlLimit = $limit+1;
  75. }
  76. if ($fld_blockinfo) {
  77. $this->addTables('ipblocks');
  78. $this->addTables('user', 'u2');
  79. $u2 = $this->getAliasedName('user', 'u2');
  80. $this->addJoinConds(array(
  81. 'ipblocks' => array('LEFT JOIN', 'ipb_user=u1.user_id'),
  82. $u2 => array('LEFT JOIN', 'ipb_by=u2.user_id')));
  83. $this->addFields(array('ipb_reason', 'u2.user_name blocker_name'));
  84. }
  85. $this->addOption('LIMIT', $sqlLimit);
  86. $this->addFields('u1.user_name');
  87. $this->addFieldsIf('u1.user_editcount', $fld_editcount);
  88. $this->addFieldsIf('u1.user_registration', $fld_registration);
  89. $this->addOption('ORDER BY', 'u1.user_name');
  90. $res = $this->select(__METHOD__);
  91. $data = array ();
  92. $count = 0;
  93. $lastUserData = false;
  94. $lastUser = false;
  95. $result = $this->getResult();
  96. //
  97. // This loop keeps track of the last entry.
  98. // For each new row, if the new row is for different user then the last, the last entry is added to results.
  99. // Otherwise, the group of the new row is appended to the last entry.
  100. // The setContinue... is more complex because of this, and takes into account the higher sql limit
  101. // to make sure all rows that belong to the same user are received.
  102. //
  103. while (true) {
  104. $row = $db->fetchObject($res);
  105. $count++;
  106. if (!$row || $lastUser !== $row->user_name) {
  107. // Save the last pass's user data
  108. if (is_array($lastUserData))
  109. {
  110. $fit = $result->addValue(array('query', $this->getModuleName()),
  111. null, $lastUserData);
  112. if(!$fit)
  113. {
  114. $this->setContinueEnumParameter('from',
  115. $this->keyToTitle($lastUserData['name']));
  116. break;
  117. }
  118. }
  119. // No more rows left
  120. if (!$row)
  121. break;
  122. if ($count > $limit) {
  123. // We've reached the one extra which shows that there are additional pages to be had. Stop here...
  124. $this->setContinueEnumParameter('from', $this->keyToTitle($row->user_name));
  125. break;
  126. }
  127. // Record new user's data
  128. $lastUser = $row->user_name;
  129. $lastUserData = array( 'name' => $lastUser );
  130. if ($fld_blockinfo) {
  131. $lastUserData['blockedby'] = $row->blocker_name;
  132. $lastUserData['blockreason'] = $row->ipb_reason;
  133. }
  134. if ($fld_editcount)
  135. $lastUserData['editcount'] = intval($row->user_editcount);
  136. if ($fld_registration)
  137. $lastUserData['registration'] = wfTimestamp(TS_ISO_8601, $row->user_registration);
  138. }
  139. if ($sqlLimit == $count) {
  140. // BUG! database contains group name that User::getAllGroups() does not return
  141. // TODO: should handle this more gracefully
  142. ApiBase :: dieDebug(__METHOD__,
  143. 'MediaWiki configuration error: the database contains more user groups than known to User::getAllGroups() function');
  144. }
  145. // Add user's group info
  146. if ($fld_groups && !is_null($row->ug_group2)) {
  147. $lastUserData['groups'][] = $row->ug_group2;
  148. $result->setIndexedTagName($lastUserData['groups'], 'g');
  149. }
  150. }
  151. $db->freeResult($res);
  152. $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'u');
  153. }
  154. public function getAllowedParams() {
  155. return array (
  156. 'from' => null,
  157. 'prefix' => null,
  158. 'group' => array(
  159. ApiBase :: PARAM_TYPE => User::getAllGroups()
  160. ),
  161. 'prop' => array (
  162. ApiBase :: PARAM_ISMULTI => true,
  163. ApiBase :: PARAM_TYPE => array (
  164. 'blockinfo',
  165. 'groups',
  166. 'editcount',
  167. 'registration'
  168. )
  169. ),
  170. 'limit' => array (
  171. ApiBase :: PARAM_DFLT => 10,
  172. ApiBase :: PARAM_TYPE => 'limit',
  173. ApiBase :: PARAM_MIN => 1,
  174. ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
  175. ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
  176. ),
  177. 'witheditsonly' => false,
  178. );
  179. }
  180. public function getParamDescription() {
  181. return array (
  182. 'from' => 'The user name to start enumerating from.',
  183. 'prefix' => 'Search for all page titles that begin with this value.',
  184. 'group' => 'Limit users to a given group name',
  185. 'prop' => array(
  186. 'What pieces of information to include.',
  187. '`groups` property uses more server resources and may return fewer results than the limit.'),
  188. 'limit' => 'How many total user names to return.',
  189. 'witheditsonly' => 'Only list users who have made edits',
  190. );
  191. }
  192. public function getDescription() {
  193. return 'Enumerate all registered users';
  194. }
  195. protected function getExamples() {
  196. return array (
  197. 'api.php?action=query&list=allusers&aufrom=Y',
  198. );
  199. }
  200. public function getVersion() {
  201. return __CLASS__ . ': $Id: ApiQueryAllUsers.php 46845 2009-02-05 14:30:59Z catrope $';
  202. }
  203. }