Fix double-compression; fix missing deletion reason; fix html insertion attack; fix...
[lhc/web/wiklou.git] / includes / DatabaseFunctions.php
1 <?
2 include_once( "FulltextStoplist.php" );
3 include_once( "CacheManager.php" );
4
5 define( "DB_READ", -1 );
6 define( "DB_WRITE", -2 );
7 define( "DB_LAST", -3 );
8
9 $wgLastDatabaseQuery = "";
10
11 function wfGetDB( $altuser = "", $altpassword = "", $altserver = "", $altdb = "" )
12 {
13 global $wgDBserver, $wgDBuser, $wgDBpassword;
14 global $wgDBname, $wgDBconnection, $wgEmergencyContact;
15
16 $noconn = wfMsgNoDB( "noconnect", $wgDBserver );
17 $nodb = wfMsgNoDB( "nodb", $wgDBname );
18
19 $helpme = "\n<p>If this error persists after reloading and clearing " .
20 "your browser cache, please notify the <a href=\"mailto:" .
21 $wgEmergencyContact . "\">Wikipedia developers</a>.</p>";
22
23 if ( $altuser != "" ) {
24 $serve = ($altserver ? $altserver : $wgDBserver );
25 $db = ($altdb ? $altdb : $wgDBname );
26 $wgDBconnection = mysql_connect( $serve, $altuser, $altpassword )
27 or die( "bad sql user" );
28 mysql_select_db( $db, $wgDBconnection ) or die(
29 htmlspecialchars(mysql_error()) );
30 }
31
32 if ( ! $wgDBconnection ) {
33 @$wgDBconnection = mysql_pconnect( $wgDBserver, $wgDBuser, $wgDBpassword )
34 or wfEmergencyAbort();
35
36 if( !mysql_select_db( $wgDBname, $wgDBconnection ) ) {
37 /* Persistent connections may become stuck in an unusable state */
38 wfDebug( "Persistent connection is broken?\n", true );
39
40 @$wgDBconnection = mysql_connect( $wgDBserver, $wgDBuser, $wgDBpassword )
41 or wfEmergencyAbort();
42
43 @mysql_select_db( $wgDBname, $wgDBconnection )
44 or wfEmergencyAbort();
45 }
46 }
47 # mysql_ping( $wgDBconnection );
48 return $wgDBconnection;
49 }
50
51 /* Call this function if we couldn't contact the database...
52 We'll try to use the cache to display something in the meantime */
53 function wfEmergencyAbort( $msg = "" ) {
54 global $wgTitle, $wgUseFileCache, $title, $wgOutputEncoding;
55
56 header( "Content-type: text/html; charset=$wgOutputEncoding" );
57 if($msg == "") $msg = wfMsgNoDB( "noconnect" );
58 $text = $msg;
59
60 if($wgUseFileCache) {
61 if($wgTitle) {
62 $t =& $wgTitle;
63 } else {
64 if($title) {
65 $t = Title::newFromURL( $title );
66 } else {
67 $t = Title::newFromText( wfMsgNoDB( "mainpage" ) );
68 }
69 }
70
71 $cache = new CacheManager( $t );
72 if( $cache->isFileCached() ) {
73 $msg = "<p style='color: red'><b>$msg<br>\n" .
74 wfMsgNoDB( "cachederror" ) . "</b></p>\n";
75
76 $tag = "<div id='article'>";
77 $text = str_replace(
78 $tag,
79 $tag . $msg,
80 $cache->fetchPageText() );
81 }
82 }
83
84 /* Don't cache error pages! They cause no end of trouble... */
85 header( "Cache-control: none" );
86 header( "Pragma: nocache" );
87 echo $text;
88 exit;
89 }
90
91 # $db: DB_READ = -1 read from slave (or only server)
92 # DB_WRITE = -2 write to master (or only server)
93 # 0,1,2,... query a database with a specific index
94 # Replication is not actually implemented just yet
95 function wfQuery( $sql, $db, $fname = "" )
96 {
97 global $wgLastDatabaseQuery, $wgOut, $wgDebugDumpSql;
98 global $wgProfiling;
99
100 if ( $wgProfiling ) {
101 # wfGeneralizeSQL will probably cut down the query to reasonable
102 # logging size most of the time. The substr is really just a sanity check.
103 $profName = "wfQuery: " . substr( wfGeneralizeSQL( $sql ), 0, 255 );
104
105 wfProfileIn( $profName );
106 }
107
108 if ( !is_numeric( $db ) ) {
109 # Someone has tried to call this the old way
110 $wgOut->fatalError( wfMsgNoDB( "wrong_wfQuery_params", $db, $sql ) );
111 }
112
113 $wgLastDatabaseQuery = $sql;
114
115 if( $wgDebugDumpSql ) {
116 $sqlx = substr( $sql, 0, 500 );
117 $sqlx = wordwrap(strtr($sqlx,"\t\n"," "));
118 wfDebug( "SQL: $sqlx\n" );
119 }
120
121 $conn = wfGetDB();
122 $ret = mysql_query( $sql, $conn );
123
124 if ( false === $ret ) {
125 $wgOut->databaseError( $fname );
126 exit;
127 }
128
129 if ( $wgProfiling ) {
130 wfProfileOut( $profName );
131 }
132 return $ret;
133 }
134
135 function wfFreeResult( $res ) { mysql_free_result( $res ); }
136 function wfFetchObject( $res ) { return mysql_fetch_object( $res ); }
137 function wfNumRows( $res ) { return mysql_num_rows( $res ); }
138 function wfNumFields( $res ) { return mysql_num_fields( $res ); }
139 function wfFieldName( $res, $n ) { return mysql_field_name( $res, $n ); }
140 function wfInsertId() { return mysql_insert_id( wfGetDB() ); }
141 function wfDataSeek( $res, $row ) { return mysql_data_seek( $res, $row ); }
142 function wfLastErrno() { return mysql_errno(); }
143 function wfLastError() { return mysql_error(); }
144 function wfAffectedRows() { return mysql_affected_rows( wfGetDB() ); }
145
146 function wfLastDBquery()
147 {
148 global $wgLastDatabaseQuery;
149 return $wgLastDatabaseQuery;
150 }
151
152 function wfSetSQL( $table, $var, $value, $cond )
153 {
154 $sql = "UPDATE $table SET $var = '" .
155 wfStrencode( $value ) . "' WHERE ($cond)";
156 wfQuery( $sql, DB_WRITE, "wfSetSQL" );
157 }
158
159 function wfGetSQL( $table, $var, $cond )
160 {
161 $sql = "SELECT $var FROM $table WHERE ($cond)";
162 $result = wfQuery( $sql, DB_READ, "wfGetSQL" );
163
164 $ret = "";
165 if ( mysql_num_rows( $result ) > 0 ) {
166 $s = mysql_fetch_object( $result );
167 $ret = $s->$var;
168 mysql_free_result( $result );
169 }
170 return $ret;
171 }
172
173 function wfStrencode( $s )
174 {
175 return addslashes( $s );
176 }
177
178 # Ideally we'd be using actual time fields in the db
179 function wfTimestamp2Unix( $ts ) {
180 return gmmktime( ( (int)substr( $ts, 8, 2) ),
181 (int)substr( $ts, 10, 2 ), (int)substr( $ts, 12, 2 ),
182 (int)substr( $ts, 4, 2 ), (int)substr( $ts, 6, 2 ),
183 (int)substr( $ts, 0, 4 ) );
184 }
185
186 function wfUnix2Timestamp( $unixtime ) {
187 return gmdate( "YmdHis", $unixtime );
188 }
189
190 function wfTimestampNow() {
191 # return NOW
192 return gmdate( "YmdHis" );
193 }
194
195 # Sorting hack for MySQL 3, which doesn't use index sorts for DESC
196 function wfInvertTimestamp( $ts ) {
197 return strtr(
198 $ts,
199 "0123456789",
200 "9876543210"
201 );
202 }
203
204 # Removes most variables from an SQL query and replaces them with X or N for numbers.
205 # It's only slightly flawed. Don't use for anything important.
206 function wfGeneralizeSQL( $sql )
207 {
208 # This could be done faster with some arrays and a single preg_replace,
209 # but this show more clearly what's going on. Which may be a good thing.
210 $sql = preg_replace( "/'.*?[^\\\\]'/", "'X'", $sql );
211 $sql = preg_replace ( "/-?\d+/" , "N", $sql);
212 $sql = preg_replace ( "/\s+/", " ", $sql);
213 return $sql;
214 }
215
216 function wfFieldExists( $table, $field )
217 {
218 $fname = "wfFieldExists";
219 $res = wfQuery( "DESCRIBE $table", DB_READ, $fname );
220 $found = false;
221
222 while ( $row = wfFetchObject( $res ) ) {
223 if ( $row->Field == $field ) {
224 $found = true;
225 break;
226 }
227 }
228 return $found;
229 }
230
231 function wfIndexExists( $table, $index )
232 {
233 global $wgDBname;
234 $fname = "wfIndexExists";
235 $sql = "SHOW INDEXES FROM $table";
236 $res = wfQuery( $sql, DB_READ, $fname );
237 $found = false;
238 while ( $row = wfFetchObject( $res ) ) {
239 if ( $row->Key_name == $index ) {
240 $found = true;
241 break;
242 }
243 }
244 return $found;
245 }
246 ?>