Bug 589: make random selection slightly more random. PHP's
[lhc/web/wiklou.git] / includes / SpecialAsksql.php
1 <?php
2 /**
3 * If enabled through $wgAllowSysopQueries = true, this class
4 * let users with sysop right the possibility to make sql queries
5 * against the cur table.
6 * Heavy queries could slow down the database specially for the
7 * biggest wikis.
8 *
9 * @package MediaWiki
10 * @subpackage SpecialPage
11 */
12
13 /**
14 *
15 */
16 function wfSpecialAsksql() {
17 global $wgUser, $wgOut, $wgRequest, $wgAllowSysopQueries;
18
19 if( !$wgAllowSysopQueries ) {
20 $wgOut->errorpage( "nosuchspecialpage", "nospecialpagetext" );
21 return;
22 }
23 if( !$wgUser->isSysop() ) {
24 $wgOut->sysopRequired();
25 return;
26 }
27
28 if( $wgRequest->wasPosted() ) {
29 $query = $wgRequest->getVal( 'wpSqlQuery' );
30 $action = $wgRequest->getVal( 'action' );
31 } else {
32 $query = "";
33 $action = "";
34 }
35 $f = new SqlQueryForm( $query);
36
37 if ( "submit" == $action ) {
38 $f->doSubmit();
39 } else {
40 $f->showForm( '' );
41 }
42 }
43
44 /**
45 * @access private
46 * @package MediaWiki
47 * @subpackage SpecialPage
48 */
49 class SqlQueryForm {
50 var $query = '';
51
52 function SqlQueryForm( $query ) {
53 $this->query = $query;
54 }
55
56 function showForm( $err ) {
57 global $wgOut, $wgUser, $wgLang;
58 global $wgLogQueries;
59
60 $wgOut->setPagetitle( wfMsg( "asksql" ) );
61 $note = wfMsg( "asksqltext" );
62 if($wgLogQueries)
63 $note .= " " . wfMsg( "sqlislogged" );
64 $wgOut->addWikiText( $note );
65
66 if ( "" != $err ) {
67 $wgOut->addHTML( "<p><font color='red' size='+1'>" . htmlspecialchars($err) . "</font>\n" );
68 }
69 if ( ! $this->query ) { $this->query = "SELECT ... FROM ... WHERE ..."; }
70 $q = wfMsg( "sqlquery" );
71 $qb = wfMsg( "querybtn" );
72 $titleObj = Title::makeTitle( NS_SPECIAL, "Asksql" );
73 $action = $titleObj->escapeLocalURL( "action=submit" );
74
75 $wgOut->addHTML( "<p>
76 <form id=\"asksql\" method=\"post\" action=\"{$action}\">
77 <table border=0><tr>
78 <td align=right>{$q}:</td>
79 <td align=left>
80 <textarea name=\"wpSqlQuery\" cols=80 rows=4 wrap=\"virtual\">"
81 . htmlspecialchars($this->query) ."
82 </textarea>
83 </td>
84 </tr><tr>
85 <td>&nbsp;</td><td align=\"left\">
86 <input type=submit name=\"wpQueryBtn\" value=\"{$qb}\">
87 </td></tr></table>
88 </form>\n" );
89
90 }
91
92 function doSubmit() {
93 global $wgOut, $wgUser, $wgServer, $wgScript, $wgArticlePath, $wgLang, $wgContLang;
94 global $wgDBserver, $wgDBsqluser, $wgDBsqlpassword, $wgDBname, $wgSqlTimeout;
95
96 # Use a limit, folks!
97 $this->query = trim( $this->query );
98 if( preg_match( "/^SELECT/i", $this->query )
99 and !preg_match( "/LIMIT/i", $this->query ) ) {
100 $this->query .= " LIMIT 100";
101 }
102 $conn = Database::newFromParams( $wgDBserver, $wgDBsqluser, $wgDBsqlpassword, $wgDBname );
103
104 $this->logQuery( $this->query );
105
106 # Start timer, will kill the DB thread in $wgSqlTimeout seconds
107 $conn->startTimer( $wgSqlTimeout );
108 $res = $conn->query( $this->query, "SpecialAsksql::doSubmit" );
109 $conn->stopTimer();
110 $this->logFinishedQuery();
111
112 $n = 0;
113 @$n = $conn->numFields( $res );
114 $titleList = false;
115
116 if ( $n ) {
117 $k = array();
118 for ( $x = 0; $x < $n; ++$x ) {
119 array_push( $k, $conn->fieldName( $res, $x ) );
120 }
121
122 if ( $n == 2 && in_array( "cur_title", $k ) && in_array( "cur_namespace", $k ) ) {
123 $titleList = true;
124 }
125
126 $a = array();
127 while ( $s = $conn->fetchObject( $res ) ) {
128 array_push( $a, $s );
129 }
130 $conn->freeResult( $res );
131
132 if ( $titleList ) {
133 $r = "";
134 foreach ( $a as $y ) {
135 $sTitle = htmlspecialchars( $y->cur_title );
136 if ( $y->cur_namespace ) {
137 $sNamespace = $wgContLang->getNsText( $y->cur_namespace );
138 $link = "$sNamespace:$sTitle";
139 } else {
140 $link = "$sTitle";
141 }
142 $skin = $wgUser->getSkin();
143 $link = $skin->makeLink( $link );
144 $r .= "* [[$link]]<br>\n";
145 }
146 } else {
147
148 $r = "<table border=1 bordercolor=black cellspacing=0 " .
149 "cellpadding=2><tr>\n";
150 foreach ( $k as $x ) $r .= "<th>" . htmlspecialchars( $x ) . "</th>";
151 $r .= "</tr>\n";
152
153 foreach ( $a as $y ) {
154 $r .= "<tr>";
155 foreach ( $k as $x ) {
156 $o = $y->$x ;
157 if ( $x == "cur_title" or $x == "old_title" or $x == "rc_title") {
158 $namespace = 0;
159 if( $x == "cur_title" && isset( $y->cur_namespace ) ) $namespace = $y->cur_namespace;
160 if( $x == "old_title" && isset( $y->old_namespace ) ) $namespace = $y->old_namespace;
161 if( $x == "rc_title" && isset( $y->rc_namespace ) ) $namespace = $y->rc_namespace;
162 $title =& Title::makeTitle( $namespace, $o );
163 $o = "<a href=\"" . $title->escapeLocalUrl() . "\" class='internal'>" .
164 htmlspecialchars( $y->$x ) . "</a>" ;
165 } else {
166 $o = htmlspecialchars( $o );
167 }
168 $r .= "<td>" . $o . "</td>\n";
169 }
170 $r .= "</tr>\n";
171 }
172 $r .= "</table>\n";
173 }
174 }
175 $this->showForm( wfMsg( "querysuccessful" ) );
176 $wgOut->addHTML( "<hr>{$r}\n" );
177 }
178
179 function logQuery( $q ) {
180 global $wgSqlLogFile, $wgLogQueries, $wgUser;
181 if(!$wgLogQueries) return;
182
183 $f = fopen( $wgSqlLogFile, "a" );
184 fputs( $f, "\n\n" . wfTimestampNow() .
185 " query by " . $wgUser->getName() .
186 ":\n$q\n" );
187 fclose( $f );
188 $this->starttime = wfTime();
189 }
190
191 function logFinishedQuery() {
192 global $wgSqlLogFile, $wgLogQueries;
193 if(!$wgLogQueries) return;
194
195 $interval = wfTime() - $this->starttime;
196
197 $f = fopen( $wgSqlLogFile, "a" );
198 fputs( $f, "finished at " . wfTimestampNow() . "; took $interval secs\n" );
199 fclose( $f );
200 }
201
202 }
203
204 ?>