/** * Report and log the HTTP error. * Sends the appropriate HTTP status code and outputs an * HTML page with an error message. */ public function report() { $this->doLog(); HttpStatus::header($this->httpCode); header('Content-type: text/html; charset=utf-8'); print $this->getHTML(); }
public function execute($par = '') { $this->getOutput()->disable(); if (wfReadOnly()) { // HTTP 423 Locked HttpStatus::header(423); print 'Wiki is in read-only mode'; return; } elseif (!$this->getRequest()->wasPosted()) { HttpStatus::header(400); print 'Request must be POSTed'; return; } $optional = array('maxjobs' => 0, 'maxtime' => 30, 'type' => false, 'async' => true); $required = array_flip(array('title', 'tasks', 'signature', 'sigexpiry')); $params = array_intersect_key($this->getRequest()->getValues(), $required + $optional); $missing = array_diff_key($required, $params); if (count($missing)) { HttpStatus::header(400); print 'Missing parameters: ' . implode(', ', array_keys($missing)); return; } $squery = $params; unset($squery['signature']); $correctSignature = self::getQuerySignature($squery, $this->getConfig()->get('SecretKey')); $providedSignature = $params['signature']; $verified = is_string($providedSignature) && hash_equals($correctSignature, $providedSignature); if (!$verified || $params['sigexpiry'] < time()) { HttpStatus::header(400); print 'Invalid or stale signature provided'; return; } // Apply any default parameter values $params += $optional; if ($params['async']) { // Client will usually disconnect before checking the response, // but it needs to know when it is safe to disconnect. Until this // reaches ignore_user_abort(), it is not safe as the jobs won't run. ignore_user_abort(true); // jobs may take a bit of time // HTTP 202 Accepted HttpStatus::header(202); ob_flush(); flush(); // Once the client receives this response, it can disconnect } // Do all of the specified tasks... if (in_array('jobs', explode('|', $params['tasks']))) { $runner = new JobRunner(LoggerFactory::getInstance('runJobs')); $response = $runner->run(array('type' => $params['type'], 'maxJobs' => $params['maxjobs'] ? $params['maxjobs'] : 1, 'maxTime' => $params['maxtime'] ? $params['maxjobs'] : 30)); if (!$params['async']) { print FormatJson::encode($response, true); } } }
# big mess. if (ob_get_level() == 0) { require_once "{$IP}/includes/OutputHandler.php"; ob_start('wfOutputHandler'); } if (!defined('MW_NO_SETUP')) { require_once "{$IP}/includes/Setup.php"; } # Multiple DBs or commits might be used; keep the request as transactional as possible if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'POST') { ignore_user_abort(true); } if (!defined('MW_API') && RequestContext::getMain()->getRequest()->getHeader('Promise-Non-Write-API-Action')) { header('Cache-Control: no-cache'); header('Content-Type: text/html; charset=utf-8'); HttpStatus::header(400); $error = wfMessage('nonwrite-api-promise-error')->escaped(); $content = <<<EOT <!DOCTYPE html> <html> <head><meta charset="UTF-8" /></head> <body> {$error} </body> </html> EOT; header('Content-Length: ' . strlen($content)); echo $content; die; }
/** * Output an HTTP status code header * @since 1.26 * @param int $code Status code */ public function statusHeader($code) { HttpStatus::header($code); }
/** * Respond with HTTP 304 Not Modified if appropiate. * * If there's an If-None-Match header, respond with a 304 appropriately * and clear out the output buffer. If the client cache is too old then do nothing. * * @param ResourceLoaderContext $context * @param string $etag ETag header value * @return bool True if HTTP 304 was sent and output handled */ protected function tryRespondNotModified(ResourceLoaderContext $context, $etag) { // See RFC 2616 § 14.26 If-None-Match // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 $clientKeys = $context->getRequest()->getHeader('If-None-Match', WebRequest::GETHEADER_LIST); // Never send 304s in debug mode if ($clientKeys !== false && !$context->getDebug() && in_array($etag, $clientKeys)) { // There's another bug in ob_gzhandler (see also the comment at // the top of this function) that causes it to gzip even empty // responses, meaning it's impossible to produce a truly empty // response (because the gzip header is always there). This is // a problem because 304 responses have to be completely empty // per the HTTP spec, and Firefox behaves buggily when they're not. // See also http://bugs.php.net/bug.php?id=51579 // To work around this, we tear down all output buffering before // sending the 304. wfResetOutputBuffers(true); HttpStatus::header(304); $this->sendResponseHeaders($context, $etag, false); return true; } return false; }
/** * Provide a simple HTTP error. * * @param int|string $code * @param string $label * @param string $desc */ function wfHttpError($code, $label, $desc) { global $wgOut; HttpStatus::header($code); if ($wgOut) { $wgOut->disable(); $wgOut->sendCacheControl(); } header('Content-type: text/html; charset=utf-8'); print '<!DOCTYPE html>' . '<html><head><title>' . htmlspecialchars($label) . '</title></head><body><h1>' . htmlspecialchars($label) . '</h1><p>' . nl2br(htmlspecialchars($desc)) . "</p></body></html>\n"; }
/** * Output a thumbnail generation error message * * @param int $status * @param string $msgHtml HTML * @return void */ function wfThumbError($status, $msgHtml) { global $wgShowHostnames; header('Cache-Control: no-cache'); header('Content-Type: text/html; charset=utf-8'); if ($status == 400 || $status == 404 || $status == 429) { HttpStatus::header($status); } elseif ($status == 403) { HttpStatus::header(403); header('Vary: Cookie'); } else { HttpStatus::header(500); } if ($wgShowHostnames) { header('X-MW-Thumbnail-Renderer: ' . wfHostname()); $url = htmlspecialchars(isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''); $hostname = htmlspecialchars(wfHostname()); $debug = "<!-- {$url} -->\n<!-- {$hostname} -->\n"; } else { $debug = ''; } $content = <<<EOT <!DOCTYPE html> <html><head> <meta charset="UTF-8" /> <title>Error generating thumbnail</title> </head> <body> <h1>Error generating thumbnail</h1> <p> {$msgHtml} </p> {$debug} </body> </html> EOT; header('Content-Length: ' . strlen($content)); echo $content; }
/** * Call this function used in preparation before streaming a file. * This function does the following: * (a) sends Last-Modified, Content-type, and Content-Disposition headers * (b) cancels any PHP output buffering and automatic gzipping of output * (c) sends Content-Length header based on HTTP_IF_MODIFIED_SINCE check * * @param string $path Storage path or file system path * @param array|bool $info File stat info with 'mtime' and 'size' fields * @param array $headers Additional headers to send * @param bool $sendErrors Send error messages if errors occur (like 404) * @return int|bool READY_STREAM, NOT_MODIFIED, or false on failure */ public static function prepareForStream($path, $info, $headers = array(), $sendErrors = true) { if (!is_array($info)) { if ($sendErrors) { HttpStatus::header(404); header('Cache-Control: no-cache'); header('Content-Type: text/html; charset=utf-8'); $encFile = htmlspecialchars($path); $encScript = htmlspecialchars($_SERVER['SCRIPT_NAME']); echo "<html><body>\n\t\t\t\t\t<h1>File not found</h1>\n\t\t\t\t\t<p>Although this PHP script ({$encScript}) exists, the file requested for output\n\t\t\t\t\t({$encFile}) does not.</p>\n\t\t\t\t\t</body></html>\n\t\t\t\t\t"; } return false; } // Sent Last-Modified HTTP header for client-side caching header('Last-Modified: ' . wfTimestamp(TS_RFC2822, $info['mtime'])); // Cancel output buffering and gzipping if set wfResetOutputBuffers(); $type = self::contentTypeFromPath($path); if ($type && $type != 'unknown/unknown') { header("Content-type: {$type}"); } else { // Send a content type which is not known to Internet Explorer, to // avoid triggering IE's content type detection. Sending a standard // unknown content type here essentially gives IE license to apply // whatever content type it likes. header('Content-type: application/x-wiki'); } // Don't stream it out as text/html if there was a PHP error if (headers_sent()) { echo "Headers already sent, terminating.\n"; return false; } // Send additional headers foreach ($headers as $header) { header($header); } // Don't send if client has up to date cache if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { $modsince = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']); if (wfTimestamp(TS_UNIX, $info['mtime']) <= strtotime($modsince)) { ini_set('zlib.output_compression', 0); HttpStatus::header(304); return self::NOT_MODIFIED; // ok } } header('Content-Length: ' . $info['size']); return self::READY_STREAM; // ok }
/** * Construct the header and output it */ function sendHeaders() { if ($this->mResponseCode) { // For back-compat, it is supported that mResponseCode be a string like " 200 OK" // (with leading space and the status message after). Cast response code to an integer // to take advantage of PHP's conversion rules which will turn " 200 OK" into 200. // http://php.net/string#language.types.string.conversion $n = intval(trim($this->mResponseCode)); HttpStatus::header($n); } header("Content-Type: " . $this->mContentType); if ($this->mLastModified) { header("Last-Modified: " . $this->mLastModified); } else { header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); } if ($this->mCacheDuration) { # If CDN caches are configured, tell them to cache the response, # and tell the client to always check with the CDN. Otherwise, # tell the client to use a cached copy, without a way to purge it. if ($this->mConfig->get('UseSquid')) { # Expect explicit purge of the proxy cache, but require end user agents # to revalidate against the proxy on each visit. # Surrogate-Control controls our CDN, Cache-Control downstream caches if ($this->mConfig->get('UseESI')) { header('Surrogate-Control: max-age=' . $this->mCacheDuration . ', content="ESI/1.0"'); header('Cache-Control: s-maxage=0, must-revalidate, max-age=0'); } else { header('Cache-Control: s-maxage=' . $this->mCacheDuration . ', must-revalidate, max-age=0'); } } else { # Let the client do the caching. Cache is not purged. header("Expires: " . gmdate("D, d M Y H:i:s", time() + $this->mCacheDuration) . " GMT"); header("Cache-Control: s-maxage={$this->mCacheDuration}," . "public,max-age={$this->mCacheDuration}"); } } else { # always expired, always modified header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Pragma: no-cache"); // HTTP/1.0 } if ($this->mVary) { header("Vary: " . $this->mVary); } }
/** * Issue a standard HTTP 403 Forbidden header ($msg1-a message index, not a message) and an * error message ($msg2, also a message index), (both required) then end the script * subsequent arguments to $msg2 will be passed as parameters only for replacing in $msg2 * @param string $msg1 * @param string $msg2 */ function wfForbidden($msg1, $msg2) { global $wgImgAuthDetails; $args = func_get_args(); array_shift($args); array_shift($args); $args = isset($args[0]) && is_array($args[0]) ? $args[0] : $args; $msgHdr = wfMessage($msg1)->escaped(); $detailMsgKey = $wgImgAuthDetails ? $msg2 : 'badaccess-group0'; $detailMsg = wfMessage($detailMsgKey, $args)->escaped(); wfDebugLog('img_auth', "wfForbidden Hdr: " . wfMessage($msg1)->inLanguage('en')->text() . " Msg: " . wfMessage($msg2, $args)->inLanguage('en')->text()); HttpStatus::header(403); header('Cache-Control: no-cache'); header('Content-Type: text/html; charset=utf-8'); echo <<<ENDS <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>{$msgHdr}</title> </head> <body> <h1>{$msgHdr}</h1> <p>{$detailMsg}</p> </body> </html> ENDS; }
private static function statusHeader($code) { if (!headers_sent()) { HttpStatus::header($code); } }
/** * Send out a standard 404 message for a file * * @param string $fname Full name and path of the file to stream * @param integer $flags Bitfield of STREAM_* constants * @since 1.24 */ public static function send404Message($fname, $flags = 0) { if (($flags & self::STREAM_HEADLESS) == 0) { HttpStatus::header(404); header('Cache-Control: no-cache'); header('Content-Type: text/html; charset=utf-8'); } $encFile = htmlspecialchars($fname); $encScript = htmlspecialchars($_SERVER['SCRIPT_NAME']); echo "<!DOCTYPE html><html><body>\n\t\t\t<h1>File not found</h1>\n\t\t\t<p>Although this PHP script ({$encScript}) exists, the file requested for output\n\t\t\t({$encFile}) does not.</p>\n\t\t\t</body></html>\n\t\t\t"; }